• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bemanproject / optional26 / 12886802002

21 Jan 2025 12:20PM UTC coverage: 93.333%. Remained the same
12886802002

push

github

web-flow
Merge pull request #103 from steve-downey/refsteal-paper

R9 of paper which fixes the reference stealing bug

11 of 12 new or added lines in 1 file covered. (91.67%)

1 existing line in 1 file now uncovered.

280 of 300 relevant lines covered (93.33%)

122348.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.88
/include/beman/optional26/optional.hpp
1
// include/beman/optional26/optional.hpp -*-C++-*-
2
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3

4
#ifndef BEMAN_OPTIONAL26_OPTIONAL_HPP
5
#define BEMAN_OPTIONAL26_OPTIONAL_HPP
6

7
#include <compare>
8
#include <concepts>
9
#if defined(__cpp_lib_format_ranges)
10
#include <format>
11
#endif
12
#include <functional>
13
#include <ranges>
14
#include <type_traits>
15
#include <utility>
16

17
#include <beman/optional26/detail/iterator.hpp>
18

19
namespace beman::optional26 {
20

21
namespace detail {
22
template <typename T, typename U>
23
concept optional_eq_rel = requires(const T& t, const U& u) {
24
    { t == u } -> std::convertible_to<bool>;
25
};
26

27
template <typename T, typename U>
28
concept optional_ne_rel = requires(const T& t, const U& u) {
29
    { t != u } -> std::convertible_to<bool>;
30
};
31

32
template <typename T, typename U>
33
concept optional_lt_rel = requires(const T& t, const U& u) {
34
    { t < u } -> std::convertible_to<bool>;
35
};
36

37
template <typename T, typename U>
38
concept optional_gt_rel = requires(const T& t, const U& u) {
39
    { t > u } -> std::convertible_to<bool>;
40
};
41

42
template <typename T, typename U>
43
concept optional_le_rel = requires(const T& t, const U& u) {
44
    { t <= u } -> std::convertible_to<bool>;
45
};
46

47
template <typename T, typename U>
48
concept optional_ge_rel = requires(const T& t, const U& u) {
49
    { t >= u } -> std::convertible_to<bool>;
50
};
51
} // namespace detail
52

53
struct in_place_t {
54
    explicit in_place_t() = default;
55
};
56

57
inline constexpr in_place_t in_place{};
58

59
} // namespace beman::optional26
60

61
namespace beman::optional26 {
62
template <class T>
63
class optional; // partially freestanding
64
} // namespace beman::optional26
65

66
// Since P3168R2: Give std::optional Range Support.
67
template <class T>
68
inline constexpr bool std::ranges::enable_view<beman::optional26::optional<T>> = true;
69

70
// Iterators for optional<T&> have life times that are not tied to the optional.
71
template <class T>
72
inline constexpr bool std::ranges::enable_borrowed_range<beman::optional26::optional<T>> = std::is_reference_v<T>;
73

74
// Since P3168R2: Give std::optional Range Support.
75
#if defined(__cpp_lib_format_ranges)
76
template <class T>
77
inline constexpr auto std::format_kind<beman::optional26::optional<T>> = range_format::disabled;
78
#endif
79

80
namespace beman::optional26 {
81
template <class T>
82
concept is_derived_from_optional = requires(const T& t) { // exposition only
83
    []<class U>(const optional<U>&) {}(t);
84
};
85

86
// \ref{optional.nullopt}, no-value state indicator
87
struct nullopt_t {
88
    // Used for constructing nullopt.
89
    enum class Tag { tag };
90

91
    // Must be constexpr for nullopt_t to be literal.
92
    explicit constexpr nullopt_t(Tag) noexcept {}
93
};
94

95
/// Tag to disengage optional objects.
96
inline constexpr nullopt_t nullopt{nullopt_t::Tag::tag};
97

98
// \ref{optional.bad.access}, class bad_optional_access
99
class bad_optional_access;
100

101
// \ref{optional.relops}, relational operators
102
template <typename T, typename U>
103
constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs)
104
    requires detail::optional_eq_rel<T, U>;
105
template <typename T, typename U>
106
constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs)
107
    requires detail::optional_ne_rel<T, U>;
108
template <typename T, typename U>
109
constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs)
110
    requires detail::optional_lt_rel<T, U>;
111
template <typename T, typename U>
112
constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs)
113
    requires detail::optional_gt_rel<T, U>;
114
template <typename T, typename U>
115
constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs)
116
    requires detail::optional_le_rel<T, U>;
117
template <typename T, typename U>
118
constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs)
119
    requires detail::optional_ge_rel<T, U>;
120
template <class T, std::three_way_comparable_with<T> U>
121
constexpr std::compare_three_way_result_t<T, U> operator<=>(const optional<T>&, const optional<U>&);
122

123
// \ref{optional.nullops}, comparison with \tcode{nullopt}
124
template <class T>
125
constexpr bool operator==(const optional<T>&, nullopt_t) noexcept;
126
template <class T>
127
constexpr std::strong_ordering operator<=>(const optional<T>&, nullopt_t) noexcept;
128

129
// \ref{optional.comp.with.t}, comparison with \tcode{T}
130
template <typename T, typename U>
131
constexpr bool operator==(const optional<T>& lhs, const U& rhs)
132
    requires detail::optional_eq_rel<T, U>;
133
template <typename T, typename U>
134
constexpr bool operator==(const T& lhs, const optional<U>& rhs)
135
    requires detail::optional_eq_rel<T, U>;
136
template <typename T, typename U>
137
constexpr bool operator!=(const optional<T>& lhs, const U& rhs)
138
    requires detail::optional_ne_rel<T, U>;
139
template <typename T, typename U>
140
constexpr bool operator!=(const T& lhs, const optional<U>& rhs)
141
    requires detail::optional_ne_rel<T, U>;
142
template <typename T, typename U>
143
constexpr bool operator<(const optional<T>& lhs, const U& rhs)
144
    requires detail::optional_lt_rel<T, U>;
145
template <typename T, typename U>
146
constexpr bool operator<(const T& lhs, const optional<U>& rhs)
147
    requires detail::optional_lt_rel<T, U>;
148
template <typename T, typename U>
149
constexpr bool operator>(const optional<T>& lhs, const U& rhs)
150
    requires detail::optional_gt_rel<T, U>;
151
template <typename T, typename U>
152
constexpr bool operator>(const T& lhs, const optional<U>& rhs)
153
    requires detail::optional_gt_rel<T, U>;
154
template <typename T, typename U>
155
constexpr bool operator<=(const optional<T>& lhs, const U& rhs)
156
    requires detail::optional_le_rel<T, U>;
157
template <typename T, typename U>
158
constexpr bool operator<=(const T& lhs, const optional<U>& rhs)
159
    requires detail::optional_le_rel<T, U>;
160
template <typename T, typename U>
161
constexpr bool operator>=(const optional<T>& lhs, const U& rhs)
162
    requires detail::optional_ge_rel<T, U>;
163
template <typename T, typename U>
164
constexpr bool operator>=(const T& lhs, const optional<U>& rhs)
165
    requires detail::optional_ge_rel<T, U>;
166
template <typename T, typename U>
167
    requires(!is_derived_from_optional<U>) && std::three_way_comparable_with<T, U>
168
constexpr std::compare_three_way_result_t<T, U> operator<=>(const optional<T>& x, const U& v);
169

170
// \ref{optional.specalg}, specialized algorithms
171
template <class T>
172
constexpr void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y)))
173
    requires std::is_move_constructible_v<T> && std::is_swappable_v<T>;
174

175
template <int = 0, class T>
176
constexpr optional<std::decay_t<T>>
177
make_optional(T&&) noexcept(std::is_nothrow_constructible_v<optional<std::decay_t<T>>, T>)
178
    requires std::is_constructible_v<std::decay_t<T>, T>;
179

180
template <class T, class... Args>
181
constexpr optional<T> make_optional(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
182
    requires std::is_constructible_v<T, Args...>;
183

184
template <class T, class U, class... Args>
185
constexpr optional<T>
186
make_optional(std::initializer_list<U> il,
187
              Args&&... args) noexcept(std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>)
188
    requires std::is_constructible_v<T, std::initializer_list<U>&, Args...>;
189

190
// \ref{optional.hash}, hash support
191
template <class T>
192
struct hash;
193
template <class T>
194
struct hash<optional<T>>;
195

196
/// END [optional.syn]
197

198
namespace detail {
199
template <class T, class U>
200
concept enable_forward_value = !std::is_same_v<std::decay_t<U>, optional<T>> &&
201
                               !std::is_same_v<std::decay_t<U>, in_place_t> && std::is_constructible_v<T, U&&>;
202

203
template <class T, class U, class Other>
204
concept enable_from_other = !std::is_same_v<T, U> &&                            //
205
                            std::is_constructible_v<T, Other> &&                //
206
                            !std::is_constructible_v<T, optional<U>&> &&        //
207
                            !std::is_constructible_v<T, optional<U>&&> &&       //
208
                            !std::is_constructible_v<T, const optional<U>&> &&  //
209
                            !std::is_constructible_v<T, const optional<U>&&> && //
210
                            !std::is_convertible_v<optional<U>&, T> &&          //
211
                            !std::is_convertible_v<optional<U>&&, T> &&         //
212
                            !std::is_convertible_v<const optional<U>&, T> &&    //
213
                            !std::is_convertible_v<const optional<U>&&, T>;
214

215
template <class T, class U>
216
concept enable_assign_forward = !std::is_same_v<optional<T>, std::decay_t<U>> &&
217
                                !std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::decay_t<U>>> &&
218
                                std::is_constructible_v<T, U> && std::is_assignable_v<T&, U>;
219

220
template <class T, class U, class Other>
221
concept enable_assign_from_other =
222
    std::is_constructible_v<T, Other> && std::is_assignable_v<T&, Other> &&
223
    !std::is_constructible_v<T, optional<U>&> && !std::is_constructible_v<T, optional<U>&&> &&
224
    !std::is_constructible_v<T, const optional<U>&> && !std::is_constructible_v<T, const optional<U>&&> &&
225
    !std::is_convertible_v<optional<U>&, T> && !std::is_convertible_v<optional<U>&&, T> &&
226
    !std::is_convertible_v<const optional<U>&, T> && !std::is_convertible_v<const optional<U>&&, T> &&
227
    !std::is_assignable_v<T&, optional<U>&> && !std::is_assignable_v<T&, optional<U>&&> &&
228
    !std::is_assignable_v<T&, const optional<U>&> && !std::is_assignable_v<T&, const optional<U>&&>;
229
} // namespace detail
230

231
namespace detail {
232
template <class T>
233
concept is_optional = requires(const T& t) { // exposition only
234
    []<class U>(const optional<U>&) {}(t);
235
};
236

237
} // namespace detail
238

239
// 22.5.3.1 General[optional.optional.general]
240

241
template <class T>
242
class optional {
243
    static_assert((!std::is_same_v<T, std::remove_cv_t<in_place_t>>) &&
244
                  (!std::is_same_v<std::remove_cv_t<T>, nullopt_t>));
245
    static_assert(std::is_object_v<T> && !std::is_array_v<T>);
246

247
  public:
248
    using value_type = T;
249
    // Since P3168R2: Give std::optional Range Support.
250
    using iterator       = detail::contiguous_iterator<T,
251
                                                       optional>; // see~\ref{optional.iterators}
252
    using const_iterator = detail::contiguous_iterator<const T,
253
                                                       optional>; // see~\ref{optional.iterators}
254

255
    // \ref{optional.ctor}, constructors
256
    constexpr optional() noexcept;
257
    constexpr optional(nullopt_t) noexcept;
258
    constexpr optional(const optional& rhs)
259
        requires std::is_copy_constructible_v<T> && (!std::is_trivially_copy_constructible_v<T>);
260
    constexpr optional(const optional&)
261
        requires std::is_copy_constructible_v<T> && std::is_trivially_copy_constructible_v<T>
262
    = default;
263
    constexpr optional(optional&& rhs) noexcept(std::is_nothrow_move_constructible_v<T>)
264
        requires std::is_move_constructible_v<T> && (!std::is_trivially_move_constructible_v<T>);
265
    constexpr optional(optional&&)
266
        requires std::is_move_constructible_v<T> && std::is_trivially_move_constructible_v<T>
267
    = default;
268

269
    template <class... Args>
270
    constexpr explicit optional(in_place_t, Args&&... args)
271
        requires std::is_constructible_v<T, Args...>;
272

273
    template <class U, class... Args>
274
    constexpr explicit optional(in_place_t, std::initializer_list<U> il, Args&&... args)
275
        requires std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>;
276

277
    template <class U = T>
278
    constexpr explicit(!std::is_convertible_v<U, T>) optional(U&& u)
279
        requires detail::enable_forward_value<T, U>;
280

281
    template <class U>
282
    constexpr explicit(!std::is_convertible_v<U, T>) optional(const optional<U>& rhs)
283
        requires(!std::is_reference_v<U> && detail::enable_from_other<T, U, const U&>);
284

285
    template <class U>
286
    constexpr explicit(!std::is_convertible_v<U, T>) optional(const optional<U>& rhs)
287
        requires(std::is_reference_v<U> && detail::enable_from_other<T, U, U>);
288

289
    template <class U>
290
    constexpr explicit(!std::is_convertible_v<U, T>) optional(optional<U>&& rhs)
291
        requires(!std::is_reference_v<U> && detail::enable_from_other<T, U, U &&>);
292

293
    // \ref{optional.dtor}, destructor
294
    constexpr ~optional()
295
        requires std::is_trivially_destructible_v<T>
296
    = default;
297

298
    constexpr ~optional()
299
        requires(!std::is_trivially_destructible_v<T>);
300

301
    // \ref{optional.assign}, assignment
302
    constexpr optional& operator=(nullopt_t) noexcept;
303

304
    constexpr optional& operator=(const optional& rhs)
305
        requires std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T> &&
306
                 (!std::is_trivially_copy_assignable_v<T>);
307

308
    constexpr optional& operator=(const optional&)
309
        requires std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T> &&
310
                     std::is_trivially_copy_constructible_v<T> && std::is_trivially_copy_assignable_v<T>
311
    = default;
312

313
    constexpr optional& operator=(optional&& rhs) noexcept(std::is_nothrow_move_constructible_v<T>)
314
        requires std::is_move_constructible_v<T> && std::is_move_assignable_v<T> &&
315
                 (!std::is_trivially_move_assignable_v<T>);
316

317
    constexpr optional& operator=(optional&&)
318
        requires std::is_move_constructible_v<T> && std::is_move_assignable_v<T> &&
319
                     std::is_trivially_move_constructible_v<T> && std::is_trivially_move_assignable_v<T>
320
    = default;
321

322
    template <class U = T>
323
    constexpr optional& operator=(U&& u)
324
        requires detail::enable_assign_forward<T, U>;
325

326
    template <class U>
327
    constexpr optional& operator=(const optional<U>& rhs)
328
        requires(!std::is_reference_v<U> && detail::enable_assign_from_other<T, U, const U&>);
329

330
    template <class U>
331
    constexpr optional& operator=(const optional<U>& rhs)
332
        requires(std::is_reference_v<U> && detail::enable_assign_from_other<T, U, U>);
333

334
    template <class U>
335
    constexpr optional& operator=(optional<U>&& rhs)
336
        requires(!std::is_reference_v<U> && detail::enable_assign_from_other<T, U, U>);
337

338
    template <class... Args>
339
    constexpr T& emplace(Args&&... args);
340

341
    template <class U, class... Args>
342
    constexpr T& emplace(std::initializer_list<U> il, Args&&... args);
343

344
    // \ref{optional.swap}, swap
345
    constexpr void swap(optional& rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
346
                                                std::is_nothrow_swappable<T>::value);
347

348
    // \ref{optional.iterators}, iterator support
349
    constexpr iterator       begin() noexcept;
350
    constexpr const_iterator begin() const noexcept;
351
    constexpr iterator       end() noexcept;
352
    constexpr const_iterator end() const noexcept;
353

354
    // \ref{optional.observe}, observers
355
    constexpr const T* operator->() const;
356
    constexpr T*       operator->();
357
    constexpr T&       operator*() &;
358
    constexpr const T& operator*() const&;
359
    constexpr T&&      operator*() &&;
360
    constexpr explicit operator bool() const noexcept;
361
    constexpr bool     has_value() const noexcept;
362
    constexpr T&       value() &;
363
    constexpr const T& value() const&;
364
    constexpr T&&      value() &&;
365
    template <class U = std::remove_cv_t<T>>
366
    constexpr T value_or(U&& u) const&;
367
    template <class U = std::remove_cv_t<T>>
368
    constexpr T value_or(U&& u) &&;
369

370
    // \ref{optional.monadic}, monadic operations
371
    template <class F>
372
    constexpr auto and_then(F&& f) &;
373
    template <class F>
374
    constexpr auto and_then(F&& f) &&;
375
    template <class F>
376
    constexpr auto and_then(F&& f) const&;
377
    template <class F>
378
    constexpr auto and_then(F&& f) const&&;
379
    template <class F>
380
    constexpr auto transform(F&& f) &;
381
    template <class F>
382
    constexpr auto transform(F&& f) &&;
383
    template <class F>
384
    constexpr auto transform(F&& f) const&;
385
    template <class F>
386
    constexpr auto transform(F&& f) const&&;
387
    template <class F>
388
    constexpr optional or_else(F&& f) const&;
389
    template <class F>
390
    constexpr optional or_else(F&& f) &&;
391

392
    // \ref{optional.mod}, modifiers
393
    constexpr void reset() noexcept;
394

395
  private:
396
    struct empty {};
397
    union {
398
        empty _{};
399
        T     value_;
400
    };
401
    bool engaged_ = false;
402

403
    template <class... Args>
404
    constexpr void construct(Args&&... args) {
54✔
405
        std::construct_at(std::addressof(value_), std::forward<Args>(args)...);
54✔
406
        engaged_ = true;
52✔
407
    }
52✔
408

409
    constexpr void hard_reset() noexcept {
×
410
        std::destroy_at(std::addressof(value_));
×
411
        engaged_ = false;
×
412
    }
×
413
};
414

415
class bad_optional_access : public std::exception {
416
  public:
417
    bad_optional_access() = default;
×
418
    const char* what() const noexcept { return "Optional has no value"; }
×
419
};
420

421
// \rSec3[optional.ctor]{Constructors}
422
template <class T>
423
inline constexpr optional<T>::optional() noexcept : _(), engaged_(false) {}
90✔
424

425
template <class T>
426
inline constexpr optional<T>::optional(nullopt_t) noexcept {}
1,666,536✔
427

428
template <class T>
429
inline constexpr optional<T>::optional(const optional& rhs)
1✔
430
    requires std::is_copy_constructible_v<T> && (!std::is_trivially_copy_constructible_v<T>)
1✔
431
{
432
    if (rhs.has_value()) {
1✔
433
        construct(rhs.value_);
1✔
434
    }
435
}
1✔
436

437
template <class T>
438
inline constexpr optional<T>::optional(optional&& rhs) noexcept(std::is_nothrow_move_constructible_v<T>)
1✔
439
    requires std::is_move_constructible_v<T> && (!std::is_trivially_move_constructible_v<T>)
1✔
440
{
441
    if (rhs.has_value()) {
1✔
442
        construct(std::move(rhs.value_));
1✔
443
    }
444
}
1✔
445

446
/// Constructs the stored value in-place using the given arguments.
447
template <class T>
448
template <class... Args>
449
inline constexpr optional<T>::optional(in_place_t, Args&&... args)
2,402✔
450
    requires std::is_constructible_v<T, Args...>
451
    : value_(std::forward<Args>(args)...), engaged_(true) {}
2,410✔
452

453
template <class T>
454
template <class U, class... Args>
455
inline constexpr optional<T>::optional(in_place_t, std::initializer_list<U> il, Args&&... args)
8✔
456
    requires std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>
457
    : value_(il, std::forward<Args>(args)...), engaged_(true) {}
16✔
458

459
/// Constructs the stored value with `u`.
460
template <class T>
461
template <class U>
462
inline constexpr optional<T>::optional(U&& u)
2,400✔
463
    requires detail::enable_forward_value<T, U>
464
    : optional(in_place, std::forward<U>(u)) {}
2,400✔
465

466
/// Converting copy constructor.
467
template <class T>
468
template <class U>
469
inline constexpr optional<T>::optional(const optional<U>& rhs)
6✔
470
    requires(!std::is_reference_v<U> && detail::enable_from_other<T, U, const U&>)
6✔
471
{
472
    if (rhs.has_value()) {
6✔
473
        construct(*rhs);
6✔
474
    }
475
}
6✔
476

477
/// Converting copy constructor for U&
478
template <class T>
479
template <class U>
480
inline constexpr optional<T>::optional(const optional<U>& rhs)
16✔
481
    requires(std::is_reference_v<U> && detail::enable_from_other<T, U, U>)
16✔
482
{
483
    if (rhs.has_value()) {
16✔
484
        construct(*rhs);
16✔
485
    }
486
}
16✔
487

488
/// Converting move constructor.
489
template <class T>
490
template <class U>
491
inline constexpr optional<T>::optional(optional<U>&& rhs)
1✔
492
    requires(!std::is_reference_v<U> && detail::enable_from_other<T, U, U &&>)
1✔
493
{
494
    if (rhs.has_value()) {
1✔
495
        construct(std::move(*rhs));
1✔
496
    }
497
}
1✔
498

499
// 22.5.3.3 Destructor[optional.dtor]
500

501
template <class T>
502
inline constexpr optional<T>::~optional()
20✔
503
    requires(!std::is_trivially_destructible_v<T>)
504
{
505
    if (has_value())
20✔
506
        std::destroy_at(std::addressof(value_));
20✔
507
}
20✔
508

509
// 22.5.3.4 Assignment[optional.assign]
510

511
template <class T>
512
inline constexpr optional<T>& optional<T>::operator=(nullopt_t) noexcept {
18✔
513
    reset();
18✔
514
    return *this;
18✔
515
}
516

517
template <class T>
518
inline constexpr optional<T>& optional<T>::operator=(const optional<T>& rhs)
3✔
519
    requires std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T> &&
520
             (!std::is_trivially_copy_assignable_v<T>)
521
{
522
    if (!rhs.has_value())
3✔
523
        reset();
1✔
524
    else if (has_value())
2✔
525
        value_ = rhs.value_;
1✔
526
    else
527
        construct(rhs.value_);
1✔
528
    return *this;
3✔
529
}
530

531
template <class T>
532
inline constexpr optional<T>&
533
optional<T>::operator=(optional<T>&& rhs) noexcept(std::is_nothrow_move_constructible_v<T>)
3✔
534
    requires std::is_move_constructible_v<T> && std::is_move_assignable_v<T> &&
535
             (!std::is_trivially_move_assignable_v<T>)
536
{
537
    if (!rhs.has_value())
3✔
538
        reset();
1✔
539
    else if (has_value())
2✔
540
        value_ = std::move(rhs.value_);
1✔
541
    else
542
        construct(std::move(rhs.value_));
1✔
543
    return *this;
3✔
544
}
545

546
/// Assigns the stored value from `u`, destroying the old value if there
547
/// was one.
548
template <class T>
549
template <class U>
550
inline constexpr optional<T>& optional<T>::operator=(U&& u)
7✔
551
    requires detail::enable_assign_forward<T, U>
552
{
553
    if (has_value()) {
7✔
554
        value_ = std::forward<U>(u);
7✔
555
    } else {
556
        construct(std::forward<U>(u));
×
557
    }
558

559
    return *this;
7✔
560
}
561

562
/// Converting copy assignment operator.
563
///
564
/// Copies the value from `rhs` if there is one. Otherwise resets the
565
/// stored value in `*this`.
566
template <class T>
567
template <class U>
568
inline constexpr optional<T>& optional<T>::operator=(const optional<U>& rhs)
1✔
569
    requires(!std::is_reference_v<U> && detail::enable_assign_from_other<T, U, const U&>)
570
{
571
    if (has_value()) {
1✔
572
        if (rhs.has_value()) {
1✔
573
            value_ = *rhs;
1✔
574
        } else {
575
            hard_reset();
×
576
        }
577
    }
578

579
    else if (rhs.has_value()) {
×
580
        construct(*rhs);
×
581
    }
582

583
    return *this;
1✔
584
}
585

586
template <class T>
587
template <class U>
588
inline constexpr optional<T>& optional<T>::operator=(const optional<U>& rhs)
16✔
589
    requires(std::is_reference_v<U> && detail::enable_assign_from_other<T, U, U>)
590
{
591
    if (has_value()) {
16✔
592
        if (rhs.has_value()) {
8✔
593
            value_ = *rhs;
8✔
594
        } else {
595
            hard_reset();
×
596
        }
597
    }
598

599
    else if (rhs.has_value()) {
8✔
600
        construct(*rhs);
8✔
601
    }
602

603
    return *this;
16✔
604
}
605

606
/// Converting move assignment operator.
607
///
608
/// Moves the value from `rhs` if there is one. Otherwise resets the stored
609
/// value in `*this`.
610
template <class T>
611
template <class U>
612
inline constexpr optional<T>& optional<T>::operator=(optional<U>&& rhs)
1✔
613
    requires(!std::is_reference_v<U> && detail::enable_assign_from_other<T, U, U>)
614
{
615
    if (has_value()) {
1✔
616
        if (rhs.has_value()) {
1✔
617
            value_ = std::move(*rhs);
1✔
618
        } else {
619
            hard_reset();
×
620
        }
621
    }
622

UNCOV
623
    else if (rhs.has_value()) {
×
NEW
624
        construct(std::move(*rhs));
×
625
    }
626

627
    return *this;
1✔
628
}
629

630
/// Constructs the value in-place, destroying the current one if there is
631
/// one.
632
template <class T>
633
template <class... Args>
634
constexpr T& optional<T>::emplace(Args&&... args) {
14✔
635
    static_assert(std::is_constructible_v<T, Args&&...>);
636
    *this = nullopt;
14✔
637
    construct(std::forward<Args>(args)...);
14✔
638
    return value();
12✔
639
}
640

641
template <class T>
642
template <class U, class... Args>
643
constexpr T& optional<T>::emplace(std::initializer_list<U> il, Args&&... args) {
644
    static_assert(std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>);
645
    *this = nullopt;
646
    construct(il, std::forward<Args>(args)...);
647
    return value();
648
}
649

650
// 22.5.3.5 Swap[optional.swap]
651
/// Swaps this optional with the other.
652
///
653
/// If neither optionals have a value, nothing happens.
654
/// If both have a value, the values are swapped.
655
/// If one has a value, it is moved to the other and the movee is left
656
/// valueless.
657
template <class T>
658
inline constexpr void optional<T>::swap(optional<T>& rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
3✔
659
                                                                   std::is_nothrow_swappable<T>::value) {
660
    static_assert(std::is_move_constructible_v<T>);
661
    using std::swap;
662
    if (has_value()) {
3✔
663
        if (rhs.has_value()) {
2✔
664
            swap(value(), *rhs);
1✔
665
        } else {
666
            std::construct_at(std::addressof(rhs.value_), std::move(value_));
1✔
667
            value_.T::~T();
1✔
668
        }
669
    } else if (rhs.has_value()) {
1✔
670
        std::construct_at(std::addressof(value_), std::move(rhs.value_));
1✔
671
        rhs.value_.T::~T();
1✔
672
    }
673
    swap(engaged_, rhs.engaged_);
3✔
674
}
3✔
675

676
// 22.5.3.6 Iterator support[optional.iterators]
677
// Since P3168R2: Give std::optional Range Support.
678
template <class T>
679
inline constexpr optional<T>::iterator optional<T>::begin() noexcept {
3,333,864✔
680
    return iterator(has_value() ? std::addressof(value_) : nullptr);
3,333,864✔
681
}
682

683
template <class T>
684
inline constexpr optional<T>::const_iterator optional<T>::begin() const noexcept {
48✔
685
    return const_iterator(has_value() ? std::addressof(value_) : nullptr);
48✔
686
}
687
template <class T>
688
inline constexpr optional<T>::iterator optional<T>::end() noexcept {
1,667,040✔
689
    return begin() + has_value();
1,667,040✔
690
}
691

692
template <class T>
693
inline constexpr optional<T>::const_iterator optional<T>::end() const noexcept {
24✔
694
    return begin() + has_value();
24✔
695
}
696

697
// 22.5.3.7 Observers[optional.observe]
698

699
/// Returns a pointer to the stored value
700
template <class T>
701
inline constexpr const T* optional<T>::operator->() const {
3✔
702
    return std::addressof(value_);
3✔
703
}
704

705
template <class T>
706
inline constexpr T* optional<T>::operator->() {
44✔
707
    return std::addressof(value_);
44✔
708
}
709

710
/// Returns the stored value
711
template <class T>
712
inline constexpr T& optional<T>::operator*() & {
154✔
713
    return value_;
154✔
714
}
715

716
template <class T>
717
inline constexpr const T& optional<T>::operator*() const& {
2,282✔
718
    return value_;
2,282✔
719
}
720

721
template <class T>
722
inline constexpr T&& optional<T>::operator*() && {
4✔
723
    return std::move(value_);
4✔
724
}
725

726
template <class T>
727
inline constexpr optional<T>::operator bool() const noexcept {
2,550✔
728
    return engaged_;
2,550✔
729
}
730

731
/// Returns whether or not the optional has a value
732
template <class T>
733
inline constexpr bool optional<T>::has_value() const noexcept {
5,001,326✔
734
    return engaged_;
5,001,326✔
735
}
736

737
/// Returns the contained value if there is one, otherwise throws
738
/// bad_optional_access
739
template <class T>
740
inline constexpr T& optional<T>::value() & {
85✔
741
    if (has_value())
85✔
742
        return value_;
85✔
743
    throw bad_optional_access();
×
744
}
745
template <class T>
746
inline constexpr const T& optional<T>::value() const& {
3✔
747
    if (has_value())
3✔
748
        return value_;
3✔
749
    throw bad_optional_access();
×
750
}
751
template <class T>
752
inline constexpr T&& optional<T>::value() && {
2✔
753
    if (has_value())
2✔
754
        return std::move(value_);
2✔
755
    throw bad_optional_access();
×
756
}
757

758
/// Returns the stored value if there is one, otherwise returns `u`
759
template <class T>
760
template <class U>
761
inline constexpr T optional<T>::value_or(U&& u) const& {
2✔
762
    static_assert(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>);
763
    return has_value() ? value() : static_cast<T>(std::forward<U>(u));
2✔
764
}
765

766
template <class T>
767
template <class U>
768
inline constexpr T optional<T>::value_or(U&& u) && {
769
    static_assert(std::is_move_constructible_v<T>);
770
    static_assert(std::is_convertible_v<decltype(u), T>, "Must be able to convert u to T");
771
    return has_value() ? std::move(value()) : static_cast<T>(std::forward<U>(u));
772
}
773

774
// 22.5.3.8 Monadic operations[optional.monadic]
775
template <class T>
776
template <class F>
777
constexpr auto optional<T>::and_then(F&& f) & {
14✔
778
    using U = std::invoke_result_t<F, T&>;
779
    static_assert(detail::is_optional<std::remove_cvref_t<U>>);
780
    if (has_value()) {
14✔
781
        return std::invoke(std::forward<F>(f), value_);
8✔
782
    } else {
783
        return std::remove_cvref_t<U>();
6✔
784
    }
785
}
786

787
template <class T>
788
template <class F>
789
constexpr auto optional<T>::and_then(F&& f) && {
6✔
790
    using U = std::invoke_result_t<F, T&&>;
791
    static_assert(detail::is_optional<std::remove_cvref_t<U>>);
792
    if (has_value()) {
6✔
793
        return std::invoke(std::forward<F>(f), std::move(value_));
4✔
794
    } else {
795
        return std::remove_cvref_t<U>();
2✔
796
    }
797
}
798

799
template <class T>
800
template <class F>
801
constexpr auto optional<T>::and_then(F&& f) const& {
6✔
802
    using U = std::invoke_result_t<F, const T&>;
803
    static_assert(detail::is_optional<std::remove_cvref_t<U>>);
804
    if (has_value()) {
6✔
805
        return std::invoke(std::forward<F>(f), value_);
4✔
806
    } else {
807
        return std::remove_cvref_t<U>();
2✔
808
    }
809
}
810

811
template <class T>
812
template <class F>
813
constexpr auto optional<T>::and_then(F&& f) const&& {
4✔
814
    using U = std::invoke_result_t<F, const T&&>;
815
    static_assert(detail::is_optional<std::remove_cvref_t<U>>);
816
    if (has_value()) {
4✔
817
        return std::invoke(std::forward<F>(f), std::move(value_));
2✔
818
    } else {
819
        return std::remove_cvref_t<U>();
2✔
820
    }
821
}
822

823
/// Carries out some operation on the stored object if there is one.
824
template <class T>
825
template <class F>
826
constexpr auto optional<T>::transform(F&& f) & {
22✔
827
    using U = std::invoke_result_t<F, T&>;
828
    static_assert(!std::is_array_v<U>);
829
    static_assert(!std::is_same_v<U, in_place_t>);
830
    static_assert(!std::is_same_v<U, nullopt_t>);
831
    static_assert(std::is_object_v<U> || std::is_reference_v<U>); /// References now allowed
832
    return (has_value()) ? optional<U>{std::invoke(std::forward<F>(f), value_)} : optional<U>{};
22✔
833
}
834

835
template <class T>
836
template <class F>
837
constexpr auto optional<T>::transform(F&& f) && {
12✔
838
    using U = std::invoke_result_t<F, T&&>;
839
    static_assert(!std::is_array_v<U>);
840
    static_assert(!std::is_same_v<U, in_place_t>);
841
    static_assert(!std::is_same_v<U, nullopt_t>);
842
    static_assert(std::is_object_v<U> || std::is_reference_v<U>); /// References now allowed
843
    return (has_value()) ? optional<U>{std::invoke(std::forward<F>(f), std::move(value_))} : optional<U>{};
12✔
844
}
845

846
template <class T>
847
template <class F>
848
constexpr auto optional<T>::transform(F&& f) const& {
12✔
849
    using U = std::invoke_result_t<F, const T&>;
850
    static_assert(!std::is_array_v<U>);
851
    static_assert(!std::is_same_v<U, in_place_t>);
852
    static_assert(!std::is_same_v<U, nullopt_t>);
853
    static_assert(std::is_object_v<U> || std::is_reference_v<U>); /// References now allowed
854
    return (has_value()) ? optional<U>{std::invoke(std::forward<F>(f), value_)} : optional<U>{};
12✔
855
}
856

857
template <class T>
858
template <class F>
859
constexpr auto optional<T>::transform(F&& f) const&& {
8✔
860
    using U = std::invoke_result_t<F, const T&>;
861
    static_assert(!std::is_array_v<U>);
862
    static_assert(!std::is_same_v<U, in_place_t>);
863
    static_assert(!std::is_same_v<U, nullopt_t>);
864
    static_assert(std::is_object_v<U> || std::is_reference_v<U>); /// References now allowed
865
    return (has_value()) ? optional<U>{std::invoke(std::forward<F>(f), value_)} : optional<U>{};
8✔
866
}
867

868
/// Calls `f` if the optional is empty
869
template <class T>
870
template <class F>
871
constexpr optional<T> optional<T>::or_else(F&& f) const& {
4✔
872
    static_assert(std::is_same_v<std::remove_cvref_t<std::invoke_result_t<F>>, optional>);
873
    if (has_value())
4✔
874
        return value_;
2✔
875

876
    return std::forward<F>(f)();
2✔
877
}
878

879
template <class T>
880
template <class F>
881
constexpr optional<T> optional<T>::or_else(F&& f) && {
4✔
882
    static_assert(std::is_same_v<std::remove_cvref_t<std::invoke_result_t<F>>, optional>);
883
    if (has_value())
4✔
884
        return std::move(value_);
2✔
885

886
    return std::forward<F>(f)();
2✔
887
}
888

889
// 22.5.3.9 Modifiers[optional.mod]
890
template <class T>
891
constexpr void optional<T>::reset() noexcept {
34✔
892
    if constexpr (!std::is_trivially_destructible_v<T>) {
893
        if (has_value())
894
            value_.~T();
895
    }
896
    engaged_ = false;
34✔
897
}
34✔
898

899
// 22.5.4 No-value state indicator[optional.nullopt]
900

901
// 22.5.5 Class bad_optional_access[optional.bad.access]
902

903
// 22.5.6 Relational operators[optional.relops]
904
template <typename T, typename U>
905
constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs)
40✔
906
    requires detail::optional_eq_rel<T, U>
907
{
908
    return static_cast<bool>(lhs) == static_cast<bool>(rhs) && (!lhs || *lhs == *rhs);
40✔
909
}
910

911
template <typename T, typename U>
912
constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs)
24✔
913
    requires detail::optional_ne_rel<T, U>
914
{
915
    return static_cast<bool>(lhs) != static_cast<bool>(rhs) || (static_cast<bool>(lhs) && *lhs != *rhs);
24✔
916
}
917

918
template <typename T, typename U>
919
constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs)
24✔
920
    requires detail::optional_lt_rel<T, U>
921
{
922
    return static_cast<bool>(rhs) && (!lhs || *lhs < *rhs);
24✔
923
}
924

925
template <typename T, typename U>
926
constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs)
18✔
927
    requires detail::optional_gt_rel<T, U>
928
{
929
    return static_cast<bool>(lhs) && (!rhs || *lhs > *rhs);
18✔
930
}
931

932
template <typename T, typename U>
933
constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs)
20✔
934
    requires detail::optional_le_rel<T, U>
935
{
936
    return !lhs || (static_cast<bool>(rhs) && *lhs <= *rhs);
20✔
937
}
938

939
template <typename T, typename U>
940
constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs)
16✔
941
    requires detail::optional_ge_rel<T, U>
942
{
943
    return !rhs || (static_cast<bool>(lhs) && *lhs >= *rhs);
16✔
944
}
945

946
template <typename T, std::three_way_comparable_with<T> U>
947
constexpr std::compare_three_way_result_t<T, U> operator<=>(const optional<T>& x, const optional<U>& y) {
948
    return x && y ? *x <=> *y : bool(x) <=> bool(y);
949
}
950

951
// 22.5.7 Comparison with nullopt[optional.nullops]
952
template <class T>
953
constexpr bool operator==(const optional<T>& lhs, nullopt_t) noexcept {
64✔
954
    return !lhs;
64✔
955
}
956

957
template <class T>
958
constexpr std::strong_ordering operator<=>(const optional<T>& x, nullopt_t) noexcept {
128✔
959
    return bool(x) <=> false;
128✔
960
}
961

962
// 22.5.8 Comparison with T[optional.comp.with.t]
963
template <typename T, typename U>
964
constexpr bool operator==(const optional<T>& lhs, const U& rhs)
38✔
965
    requires detail::optional_eq_rel<T, U>
966
{
967
    return lhs && *lhs == rhs;
38✔
968
}
969

970
template <typename T, typename U>
971
constexpr bool operator==(const T& lhs, const optional<U>& rhs)
16✔
972
    requires detail::optional_eq_rel<T, U>
973
{
974
    return rhs && lhs == *rhs;
16✔
975
}
976

977
template <typename T, typename U>
978
constexpr bool operator!=(const optional<T>& lhs, const U& rhs)
16✔
979
    requires detail::optional_ne_rel<T, U>
980
{
981
    return !lhs || *lhs != rhs;
16✔
982
}
983

984
template <typename T, typename U>
985
constexpr bool operator!=(const T& lhs, const optional<U>& rhs)
16✔
986
    requires detail::optional_ne_rel<T, U>
987
{
988
    return !rhs || lhs != *rhs;
16✔
989
}
990

991
template <typename T, typename U>
992
constexpr bool operator<(const optional<T>& lhs, const U& rhs)
16✔
993
    requires detail::optional_lt_rel<T, U>
994
{
995
    return !lhs || *lhs < rhs;
16✔
996
}
997

998
template <typename T, typename U>
999
constexpr bool operator<(const T& lhs, const optional<U>& rhs)
16✔
1000
    requires detail::optional_lt_rel<T, U>
1001
{
1002
    return rhs && lhs < *rhs;
16✔
1003
}
1004

1005
template <typename T, typename U>
1006
constexpr bool operator>(const optional<T>& lhs, const U& rhs)
16✔
1007
    requires detail::optional_gt_rel<T, U>
1008
{
1009
    return lhs && *lhs > rhs;
16✔
1010
}
1011

1012
template <typename T, typename U>
1013
constexpr bool operator>(const T& lhs, const optional<U>& rhs)
16✔
1014
    requires detail::optional_gt_rel<T, U>
1015
{
1016
    return !rhs || lhs > *rhs;
16✔
1017
}
1018

1019
template <typename T, typename U>
1020
constexpr bool operator<=(const optional<T>& lhs, const U& rhs)
16✔
1021
    requires detail::optional_le_rel<T, U>
1022
{
1023
    return !lhs || *lhs <= rhs;
16✔
1024
}
1025

1026
template <typename T, typename U>
1027
constexpr bool operator<=(const T& lhs, const optional<U>& rhs)
16✔
1028
    requires detail::optional_le_rel<T, U>
1029
{
1030
    return rhs && lhs <= *rhs;
16✔
1031
}
1032

1033
template <typename T, typename U>
1034
constexpr bool operator>=(const optional<T>& lhs, const U& rhs)
16✔
1035
    requires detail::optional_ge_rel<T, U>
1036
{
1037
    return lhs && *lhs >= rhs;
16✔
1038
}
1039

1040
template <typename T, typename U>
1041
constexpr bool operator>=(const T& lhs, const optional<U>& rhs)
16✔
1042
    requires detail::optional_ge_rel<T, U>
1043
{
1044
    return !rhs || lhs >= *rhs;
16✔
1045
}
1046

1047
template <typename T, typename U>
1048
    requires(!is_derived_from_optional<U>) && std::three_way_comparable_with<T, U>
1049
constexpr std::compare_three_way_result_t<T, U> operator<=>(const optional<T>& x, const U& v) {
1050
    return bool(x) ? *x <=> v : std::strong_ordering::less;
1051
}
1052

1053
// 22.5.9 Specialized algorithms[optional.specalg]
1054

1055
template <class T>
1056
constexpr void swap(optional<T>& lhs, optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs)))
1057
    requires std::is_move_constructible_v<T> && std::is_swappable_v<T>
1058
{
1059
    return lhs.swap(rhs);
1060
}
1061

1062
template <int, class T>
1063
constexpr optional<std::decay_t<T>>
1064
make_optional(T&& t) noexcept(std::is_nothrow_constructible_v<optional<std::decay_t<T>>, T>)
10✔
1065
    requires std::is_constructible_v<std::decay_t<T>, T>
1066
{
1067
    return optional<std::decay_t<T>>{std::forward<T>(t)};
10✔
1068
}
1069

1070
template <typename T, typename... Args>
1071
constexpr optional<T> make_optional(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
1072
    requires std::is_constructible_v<T, Args...>
1073
{
1074
    static_assert(!std::is_reference_v<T>, "May not make an optional containing a reference");
1075
    return optional<T>{in_place, std::forward<Args>(args)...};
1076
}
1077

1078
template <typename T, typename U, typename... Args>
1079
constexpr optional<T>
1080
make_optional(std::initializer_list<U> init_list,
4✔
1081
              Args&&... args) noexcept(std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>)
1082
    requires std::is_constructible_v<T, std::initializer_list<U>&, Args...>
1083
{
1084
    static_assert(!std::is_reference_v<U>, "Can not make optional from initializer_list of references.");
1085
    return optional<T>{in_place, init_list, std::forward<Args>(args)...};
4✔
1086
}
1087

1088
/****************/
1089
/* optional<T&> */
1090
/****************/
1091

1092
namespace detail {
1093

1094
#ifdef __cpp_lib_reference_from_temporary
1095
using std::reference_constructs_from_temporary_v;
1096
using std::reference_converts_from_temporary_v;
1097
#else
1098
template <class To, class From>
1099
concept reference_converts_from_temporary_v =
1100
    std::is_reference_v<To> &&
1101
    (
1102
        // A prvalue of a type similar to To, so that we're binding directly to
1103
        // the materialized prvalue of type From
1104
        (!std::is_reference_v<From> && std::is_convertible_v<std::remove_cvref_t<From>*, std::remove_cvref_t<To>*>) ||
1105
        // A value of an unrelated type, convertible to To, but only by
1106
        // materializing a To and binding a const reference; if we were trying
1107
        // to bind a non-const reference, we'd be unable to. (This is not quite
1108
        // exhaustive of the problem cases, but I think it's fairly close in
1109
        // practice.)
1110
        (std::is_lvalue_reference_v<To> && std::is_const_v<std::remove_reference_t<To>> &&
1111
         std::is_convertible_v<From, const std::remove_cvref_t<To>&&> &&
1112
         !std::is_convertible_v<From, std::remove_cvref_t<To>&>));
1113

1114
template <class To, class From>
1115
concept reference_constructs_from_temporary_v =
1116
    // This is close in practice, because cases where conversion and
1117
    // construction differ in semantics are rare.
1118
    reference_converts_from_temporary_v<To, From>;
1119
#endif
1120

1121
} // namespace detail
1122

1123
template <class T>
1124
class optional<T&> {
1125
  public:
1126
    using value_type = T;
1127
    using iterator   = detail::contiguous_iterator<T,
1128
                                                   optional>; // see [optionalref.iterators]
1129
  public:
1130
    // \ref{optionalref.ctor}, constructors
1131

1132
    constexpr optional() noexcept;
1133
    constexpr optional(nullopt_t) noexcept;
1134
    constexpr optional(const optional& rhs) noexcept = default;
1135

1136
    template <class Arg>
1137
        requires(std::is_constructible_v<T&, std::remove_cv_t<Arg>> &&
1138
                 !detail::reference_constructs_from_temporary_v<T&, Arg>)
1139
    constexpr explicit optional(in_place_t, Arg&& arg);
1140

1141
    template <class U>
1142
        requires(std::is_constructible_v<T&, U> && !(std::is_same_v<std::remove_cvref_t<U>, in_place_t>) &&
1143
                 !(std::is_same_v<std::remove_cvref_t<U>, optional>) &&
1144
                 !detail::reference_constructs_from_temporary_v<T&, U>)
1145
    constexpr explicit(!std::is_convertible_v<U, T&>) optional(U&& u) noexcept(std::is_nothrow_constructible_v<T&, U>)
182✔
1146
        : value_(std::addressof(static_cast<T&>(std::forward<U>(u)))) {}
182✔
1147

1148
    template <class U>
1149
        requires(std::is_constructible_v<T&, U> && !(std::is_same_v<std::remove_cvref_t<U>, in_place_t>) &&
1150
                 !(std::is_same_v<std::remove_cvref_t<U>, optional>) &&
1151
                 detail::reference_constructs_from_temporary_v<T&, U>)
1152
    constexpr optional(U&& u) = delete;
1153

1154
    // The full set of 4 overloads on optional<U> by value category, doubled to
1155
    // 8 by deleting if reference_constructs_from_temporary_v is true. This
1156
    // allows correct constraints by propagating the value category from the
1157
    // optional to the value within the rhs.
1158
    template <class U>
1159
        requires(std::is_constructible_v<T&, U&> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1160
                 !std::is_same_v<T&, U> && !detail::reference_constructs_from_temporary_v<T&, U&>)
1161
    constexpr explicit(!std::is_convertible_v<U&, T&>)
1162
        optional(optional<U>& rhs) noexcept(std::is_nothrow_constructible_v<T&, U&>);
1163

1164
    template <class U>
1165
        requires(std::is_constructible_v<T&, const U&> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1166
                 !std::is_same_v<T&, U> && !detail::reference_constructs_from_temporary_v<T&, const U&>)
1167
    constexpr explicit(!std::is_convertible_v<const U&, T&>)
1168
        optional(const optional<U>& rhs) noexcept(std::is_nothrow_constructible_v<T&, const U&>);
1169

1170
    template <class U>
1171
        requires(std::is_constructible_v<T&, U> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1172
                 !std::is_same_v<T&, U> && !detail::reference_constructs_from_temporary_v<T&, U>)
1173
    constexpr explicit(!std::is_convertible_v<U, T&>)
1174
        optional(optional<U>&& rhs) noexcept(noexcept(std::is_nothrow_constructible_v<T&, U>));
1175

1176
    template <class U>
1177
        requires(std::is_constructible_v<T&, const U> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1178
                 !std::is_same_v<T&, U> && !detail::reference_constructs_from_temporary_v<T&, const U>)
1179
    constexpr explicit(!std::is_convertible_v<const U, T&>)
1180
        optional(const optional<U>&& rhs) noexcept(noexcept(std::is_nothrow_constructible_v<T&, const U>));
1181

1182
    template <class U>
1183
        requires(std::is_constructible_v<T&, U&> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1184
                 !std::is_same_v<T&, U> && detail::reference_constructs_from_temporary_v<T&, U&>)
1185
    constexpr optional(optional<U>& rhs) = delete;
1186

1187
    template <class U>
1188
        requires(std::is_constructible_v<T&, const U&> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1189
                 !std::is_same_v<T&, U> && detail::reference_constructs_from_temporary_v<T&, const U&>)
1190
    constexpr optional(const optional<U>& rhs) = delete;
1191

1192
    template <class U>
1193
        requires(std::is_constructible_v<T&, U> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1194
                 !std::is_same_v<T&, U> && detail::reference_constructs_from_temporary_v<T&, U>)
1195
    constexpr optional(optional<U>&& rhs) = delete;
1196

1197
    template <class U>
1198
        requires(std::is_constructible_v<T&, const U> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1199
                 !std::is_same_v<T&, U> && detail::reference_constructs_from_temporary_v<T&, const U>)
1200
    constexpr optional(const optional<U>&& rhs) = delete;
1201

1202
    // \ref{optionalref.dtor}, destructor
1203
    constexpr ~optional() = default;
1204

1205
    // \ref{optionalref.assign}, assignment
1206
    constexpr optional& operator=(nullopt_t) noexcept;
1207

1208
    constexpr optional& operator=(const optional& rhs) noexcept = default;
1209

1210
    template <class U>
1211
        requires(std::is_constructible_v<T&, U> && !detail::reference_constructs_from_temporary_v<T&, U>)
1212
    constexpr T& emplace(U&& u) noexcept(std::is_nothrow_constructible_v<T&, U>);
1213

1214
    // \ref{optionalref.swap}, swap
1215
    constexpr void swap(optional& rhs) noexcept;
1216

1217
    // \ref{optional.iterators}, iterator support
1218
    constexpr iterator begin() const noexcept;
1219
    constexpr iterator end() const noexcept;
1220

1221
    // \ref{optionalref.observe}, observers
1222
    constexpr T*       operator->() const noexcept;
1223
    constexpr T&       operator*() const noexcept;
1224
    constexpr explicit operator bool() const noexcept;
1225
    constexpr bool     has_value() const noexcept;
1226
    constexpr T&       value() const;
1227
    template <class U>
1228
    constexpr std::remove_cv_t<T> value_or(U&& u) const;
1229

1230
    // \ref{optionalref.monadic}, monadic operations
1231
    template <class F>
1232
    constexpr auto and_then(F&& f) const;
1233
    template <class F>
1234
    constexpr auto transform(F&& f) const -> optional<std::invoke_result_t<F, T&>>;
1235
    template <class F>
1236
    constexpr optional or_else(F&& f) const;
1237

1238
    // \ref{optional.mod}, modifiers
1239
    constexpr void reset() noexcept;
1240

1241
  private:
1242
    T* value_; // exposition only
1243
};
1244

1245
//  \rSec3[optionalref.ctor]{Constructors}
1246
template <class T>
1247
constexpr optional<T&>::optional() noexcept : value_(nullptr) {}
×
1248

1249
template <class T>
1250
constexpr optional<T&>::optional(nullopt_t) noexcept : value_(nullptr) {}
1251

1252
template <class T>
1253
template <class Arg>
1254
    requires(std::is_constructible_v<T&, std::remove_cv_t<Arg>> &&
1255
             !detail::reference_constructs_from_temporary_v<T&, Arg>)
1256
constexpr optional<T&>::optional(in_place_t, Arg&& arg)
6✔
1257
    : value_(std::addressof(static_cast<T&>(std::forward<Arg>(arg)))) {}
6✔
1258

1259
// Clang is unhappy with the out-of-line definition
1260
//
1261
// template <class T>
1262
// template <class U>
1263
//     requires(std::is_constructible_v<T&, U> && !(is_same_v<remove_cvref_t<U>, in_place_t>) &&
1264
//              !(is_same_v<remove_cvref_t<U>, optional<T&>>) && !detail::reference_constructs_from_temporary_v<T&, U>)
1265
// constexpr optional<T&>::optional(U&& u) noexcept(is_nothrow_constructible_v<T&, U>)
1266
//     : value_(std::addressof(static_cast<T&>(std::forward<U>(u)))) {}
1267

1268
template <class T>
1269
template <class U>
1270
    requires(std::is_constructible_v<T&, U&> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1271
             !std::is_same_v<T&, U> && !detail::reference_constructs_from_temporary_v<T&, U&>)
1272
constexpr optional<T&>::optional(optional<U>& rhs) noexcept(std::is_nothrow_constructible_v<T&, U&>) {
24✔
1273
    if (rhs.has_value()) {
24✔
1274
        value_ = std::addressof(static_cast<T&>(rhs.value()));
12✔
1275
    } else {
1276
        value_ = nullptr;
12✔
1277
    }
1278
}
24✔
1279

1280
template <class T>
1281
template <class U>
1282
    requires(std::is_constructible_v<T&, const U&> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1283
             !std::is_same_v<T&, U> && !detail::reference_constructs_from_temporary_v<T&, const U&>)
1284
constexpr optional<T&>::optional(const optional<U>& rhs) noexcept(std::is_nothrow_constructible_v<T&, const U&>) {
1285
    if (rhs.has_value()) {
1286
        value_ = std::addressof(static_cast<T&>(rhs.value()));
1287
    } else {
1288
        value_ = nullptr;
1289
    }
1290
}
1291

1292
template <class T>
1293
template <class U>
1294
    requires(std::is_constructible_v<T&, U> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1295
             !std::is_same_v<T&, U> && !detail::reference_constructs_from_temporary_v<T&, U>)
1296
constexpr optional<T&>::optional(optional<U>&& rhs) noexcept(noexcept(std::is_nothrow_constructible_v<T&, U>)) {
4✔
1297
    if (rhs.has_value()) {
4✔
1298
        value_ = std::addressof(static_cast<T&>(std::move(rhs).value()));
4✔
1299
    } else {
1300
        value_ = nullptr;
×
1301
    }
1302
}
4✔
1303

1304
template <class T>
1305
template <class U>
1306
    requires(std::is_constructible_v<T&, const U> && !std::is_same_v<std::remove_cv_t<T>, optional<U>> &&
1307
             !std::is_same_v<T&, U> && !detail::reference_constructs_from_temporary_v<T&, const U>)
1308
constexpr optional<T&>::optional(const optional<U>&& rhs) noexcept(
1309
    noexcept(std::is_nothrow_constructible_v<T&, const U>)) {
1310
    if (rhs.has_value()) {
1311
        value_ = std::addressof(static_cast<T&>(std::move(rhs).value()));
1312
    } else {
1313
        value_ = nullptr;
1314
    }
1315
}
1316

1317
// \rSec3[optionalref.assign]{Assignment}
1318
template <class T>
1319
constexpr optional<T&>& optional<T&>::operator=(nullopt_t) noexcept {
1320
    value_ = nullptr;
1321
    return *this;
1322
}
1323

1324
template <class T>
1325
template <class U>
1326
    requires(std::is_constructible_v<T&, U> && !detail::reference_constructs_from_temporary_v<T&, U>)
1327
constexpr T& optional<T&>::emplace(U&& u) noexcept(std::is_nothrow_constructible_v<T&, U>) {
6✔
1328
    value_ = std::addressof(static_cast<T&>(std::forward<U>(u)));
6✔
1329
    return *value_;
6✔
1330
}
1331

1332
//   \rSec3[optionalref.swap]{Swap}
1333

1334
template <class T>
1335
constexpr void optional<T&>::swap(optional<T&>& rhs) noexcept {
3✔
1336
    std::swap(value_, rhs.value_);
3✔
1337
}
3✔
1338

1339
// \rSec3[optionalref.iterators]{Iterator Support}
1340

1341
template <class T>
1342
constexpr optional<T&>::iterator optional<T&>::begin() const noexcept {
20✔
1343
    return iterator(has_value() ? value_ : nullptr);
20✔
1344
};
1345

1346
template <class T>
1347
constexpr optional<T&>::iterator optional<T&>::end() const noexcept {
4✔
1348
    return begin() + has_value();
4✔
1349
}
1350

1351
// \rSec3[optionalref.observe]{Observers}
1352
template <class T>
1353
constexpr T* optional<T&>::operator->() const noexcept {
1354
    return value_;
1355
}
1356

1357
template <class T>
1358
constexpr T& optional<T&>::operator*() const noexcept {
286✔
1359
    return *value_;
286✔
1360
}
1361

1362
template <class T>
1363
constexpr optional<T&>::operator bool() const noexcept {
428✔
1364
    return value_ != nullptr;
428✔
1365
}
1366
template <class T>
1367
constexpr bool optional<T&>::has_value() const noexcept {
294✔
1368
    return value_ != nullptr;
294✔
1369
}
1370

1371
template <class T>
1372
constexpr T& optional<T&>::value() const {
44✔
1373
    if (has_value())
44✔
1374
        return *value_;
44✔
1375
    throw bad_optional_access();
×
1376
}
1377

1378
template <class T>
1379
template <class U>
1380
constexpr std::remove_cv_t<T> optional<T&>::value_or(U&& u) const {
20✔
1381
    static_assert(std::is_constructible_v<std::remove_cv_t<T>, T&>, "T must be constructible from a T&");
1382
    static_assert(std::is_convertible_v<U, std::remove_cv_t<T>>, "Must be able to convert u to T");
1383
    if (has_value()) {
20✔
1384
        return std::remove_cv_t<T>(*value_);
8✔
1385
    } else {
1386
        return std::forward<U>(u);
12✔
1387
    }
1388
}
1389

1390
//   \rSec3[optionalref.monadic]{Monadic operations}
1391
template <class T>
1392
template <class F>
1393
constexpr auto optional<T&>::and_then(F&& f) const {
31✔
1394
    using U = std::invoke_result_t<F, T&>;
1395
    static_assert(detail::is_optional<U>, "F must return an optional");
1396
    if (has_value()) {
31✔
1397
        return std::invoke(std::forward<F>(f), *value_);
19✔
1398
    } else {
1399
        return std::remove_cvref_t<U>();
12✔
1400
    }
1401
}
1402

1403
template <class T>
1404
template <class F>
1405
constexpr auto optional<T&>::transform(F&& f) const -> optional<std::invoke_result_t<F, T&>> {
50✔
1406
    using U = std::invoke_result_t<F, T&>;
1407
    static_assert(!std::is_same_v<std::remove_cvref_t<U>, in_place_t>, "Result must not be in_place_t");
1408
    static_assert(!std::is_same_v<std::remove_cvref_t<U>, nullopt_t>, "Result must not be nullopt_t");
1409
    static_assert((std::is_object_v<U> && !std::is_array_v<U>) || std::is_lvalue_reference_v<U>,
1410
                  "Result must be an non-array object or an lvalue reference");
1411
    if (has_value()) {
50✔
1412
        return optional<U>{std::invoke(std::forward<F>(f), *value_)};
30✔
1413
    } else {
1414
        return optional<U>{};
20✔
1415
    }
1416
}
1417

1418
template <class T>
1419
template <class F>
1420
constexpr optional<T&> optional<T&>::or_else(F&& f) const {
2✔
1421
    using U = std::invoke_result_t<F>;
1422
    static_assert(std::is_same_v<std::remove_cvref_t<U>, optional>);
1423
    if (has_value()) {
2✔
1424
        return *value_;
1✔
1425
    } else {
1426
        return std::forward<F>(f)();
1✔
1427
    }
1428
}
1429

1430
// \rSec3[optional.mod]{modifiers}
1431
template <class T>
1432
constexpr void optional<T&>::reset() noexcept {
1✔
1433
    value_ = nullptr;
1✔
1434
}
1✔
1435
} // namespace beman::optional26
1436

1437
namespace std {
1438
template <typename T>
1439
    requires requires(T a) {
1440
        { std::hash<remove_const_t<T>>{}(a) } -> std::convertible_to<std::size_t>;
1441
    }
1442
struct hash<beman::optional26::optional<T>> {
1443
    static_assert(!is_reference_v<T>, "hash is not enabled for reference types");
1444
    size_t operator()(const beman::optional26::optional<T>& o) const
1,004✔
1445
        noexcept(noexcept(hash<remove_const_t<T>>{}(*o))) {
1446
        if (o) {
1,004✔
1447
            return std::hash<std::remove_const_t<T>>{}(*o);
1,002✔
1448
        } else {
1449
            return 0;
2✔
1450
        }
1451
    }
1452
};
1453
} // namespace std
1454

1455
#endif // BEMAN_OPTIONAL26_OPTIONAL_HPP
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc