Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-cpp-compat.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 5.1.0
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
72#ifndef ALEPH_CPP_COMPAT_H
73#define ALEPH_CPP_COMPAT_H
74
75#include <exception>
76#include <functional>
77#include <memory>
78#include <new>
79#include <type_traits>
80#include <utility>
81
82#if __has_include(<version>)
83# include <version> // library feature-test macros (__cpp_lib_*)
84#endif
85
86// ---------------------------------------------------------------------------
87// Feature detection for selected C++23 library facilities.
88// ---------------------------------------------------------------------------
89
90#if defined(__cpp_lib_expected) && __cpp_lib_expected >= 202211L
91# define ALEPH_HAS_STD_EXPECTED 1
92#else
93# define ALEPH_HAS_STD_EXPECTED 0
94#endif
95
96#if defined(__cpp_lib_generator) && __cpp_lib_generator >= 202207L
97# define ALEPH_HAS_STD_GENERATOR 1
98#else
99# define ALEPH_HAS_STD_GENERATOR 0
100#endif
101
102#if defined(__cpp_lib_flat_map) && __cpp_lib_flat_map >= 202207L
103# define ALEPH_HAS_STD_FLAT_MAP 1
104#else
105# define ALEPH_HAS_STD_FLAT_MAP 0
106#endif
107
108#if defined(__cpp_lib_mdspan) && __cpp_lib_mdspan >= 202207L
109# define ALEPH_HAS_STD_MDSPAN 1
110#else
111# define ALEPH_HAS_STD_MDSPAN 0
112#endif
113
114// ---------------------------------------------------------------------------
115// Aleph::expected
116// ---------------------------------------------------------------------------
117
118#if ALEPH_HAS_STD_EXPECTED
119
120#include <expected>
121
122namespace Aleph {
123template <class T, class E> using expected = std::expected<T, E>;
124template <class E> using unexpected = std::unexpected<E>;
125template <class E> using bad_expected_access = std::bad_expected_access<E>;
126using std::unexpect;
127using std::unexpect_t;
128} // namespace Aleph
129
130#else // ----- C++20 / C++17 polyfill ---------------------------------------
131
132namespace Aleph {
133
134namespace cpp_compat_detail {
136template <class U>
137using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>;
138} // namespace cpp_compat_detail
139
149{
150 explicit unexpect_t() = default;
151};
152
160inline constexpr unexpect_t unexpect{};
161
181template <class E>
183{
185
186public:
201 template <class Err = E>
202 requires (not std::is_same_v<std::remove_cvref_t<Err>, unexpected> and
203 std::is_constructible_v<E, Err>)
204 constexpr explicit unexpected(Err &&e)
205 noexcept(std::is_nothrow_constructible_v<E, Err>)
206 : err_(std::forward<Err>(e)) {}
207
212 constexpr const E &error() const & noexcept { return err_; }
213
218 constexpr E &error() & noexcept { return err_; }
219
224 constexpr E &&error() && noexcept { return std::move(err_); }
225};
226
227template <class E>
229
241template <class E>
242class bad_expected_access : public std::exception
243{
245
246public:
251 explicit bad_expected_access(E e) : err_(std::move(e)) {}
252
257 [[nodiscard]] const char *what() const noexcept override
258 {
259 return "Aleph::bad_expected_access: expected holds an error, not a value";
260 }
261
266 [[nodiscard]] const E &error() const & noexcept { return err_; }
267
272 [[nodiscard]] E &error() & noexcept { return err_; }
273};
274
284template <class T, class E>
286{
287 static_assert(not std::is_same_v<std::remove_cv_t<T>, unexpect_t>,
288 "T must not be unexpect_t");
289
290 union
291 {
294 };
295 bool has_;
296
298 {
299 if (has_)
300 val_.~T();
301 else
302 err_.~E();
303 }
304
305public:
306 using value_type = T;
307 using error_type = E;
309
320 constexpr expected() : val_(), has_(true) {}
321
335 template <class U = T,
336 class = std::enable_if_t<
337 std::is_constructible_v<T, U &&> and
338 not std::is_same_v<cpp_compat_detail::remove_cvref_t<U>, expected> and
339 not std::is_same_v<cpp_compat_detail::remove_cvref_t<U>, unexpect_t>>>
340 constexpr expected(U &&v) : val_(std::forward<U>(v)), has_(true)
341 {
342 }
343
352 template <class G>
353 constexpr expected(const unexpected<G> &u) : err_(u.error()), has_(false)
354 {
355 }
356
365 template <class G>
366 constexpr expected(unexpected<G> &&u)
367 : err_(std::move(u).error()), has_(false)
368 {
369 }
370
385 template <class... Args>
386 constexpr explicit expected(unexpect_t, Args &&...args)
387 : err_(std::forward<Args>(args)...), has_(false)
388 {
389 }
390
402 {
403 if (has_)
404 ::new (static_cast<void *>(std::addressof(val_))) T(o.val_);
405 else
406 ::new (static_cast<void *>(std::addressof(err_))) E(o.err_);
407 }
408
419 expected(expected &&o) noexcept(std::is_nothrow_move_constructible_v<T> and
420 std::is_nothrow_move_constructible_v<E>)
421 : has_(o.has_)
422 {
423 if (has_)
424 ::new (static_cast<void *>(std::addressof(val_))) T(std::move(o.val_));
425 else
426 ::new (static_cast<void *>(std::addressof(err_))) E(std::move(o.err_));
427 }
428
443 {
444 if (this != std::addressof(o))
445 {
446 expected tmp(o);
447 destroy();
448 has_ = tmp.has_;
449 if (has_)
450 ::new (static_cast<void *>(std::addressof(val_))) T(std::move(tmp.val_));
451 else
452 ::new (static_cast<void *>(std::addressof(err_))) E(std::move(tmp.err_));
453 }
454 return *this;
455 }
456
470 std::is_nothrow_move_constructible_v<T> and
471 std::is_nothrow_move_constructible_v<E>)
472 {
473 if (this != std::addressof(o))
474 {
475 expected tmp(std::move(o));
476 destroy();
477 has_ = tmp.has_;
478 if (has_)
479 ::new (static_cast<void *>(std::addressof(val_))) T(std::move(tmp.val_));
480 else
481 ::new (static_cast<void *>(std::addressof(err_))) E(std::move(tmp.err_));
482 }
483 return *this;
484 }
485
494
495 // -- observers ----------------------------------------------------------
496
501 [[nodiscard]] constexpr bool has_value() const noexcept { return has_; }
502
508 [[nodiscard]] constexpr explicit operator bool() const noexcept { return has_; }
509
515 [[nodiscard]] constexpr const T &operator*() const & noexcept { return val_; }
516
522 [[nodiscard]] constexpr T &operator*() & noexcept { return val_; }
523
529 [[nodiscard]] constexpr const T *operator->() const noexcept
530 {
531 return std::addressof(val_);
532 }
533
540 {
541 return std::addressof(val_);
542 }
543
550 [[nodiscard]] constexpr const T &value() const &
551 {
552 if (not has_)
554 return val_;
555 }
556
563 [[nodiscard]] constexpr T &value() &
564 {
565 if (not has_)
567 return val_;
568 }
569
575 [[nodiscard]] constexpr const E &error() const & noexcept { return err_; }
576
582 [[nodiscard]] constexpr E &error() & noexcept { return err_; }
583
597 template <class U>
598 [[nodiscard]] constexpr T value_or(U &&default_value) const &
599 {
600 return has_ ? val_ : static_cast<T>(std::forward<U>(default_value));
601 }
602
603 // -- monadic operations -------------------------------------------------
604
620 template <class F>
621 [[nodiscard]] auto and_then(F &&f) const &
622 {
624 if (has_)
625 return std::invoke(std::forward<F>(f), val_);
626 return R(unexpected<E>(err_));
627 }
628
643 template <class F>
644 [[nodiscard]] auto transform(F &&f) const &
645 {
647 using R = expected<U, E>;
648 if (has_)
649 return R(std::invoke(std::forward<F>(f), val_));
650 return R(unexpected<E>(err_));
651 }
652
671 template <class F>
672 [[nodiscard]] auto or_else(F &&f) const &
673 {
675 if (has_)
676 return R(val_);
677 return std::invoke(std::forward<F>(f), err_);
678 }
679};
680
688template <class E>
689class expected<void, E>
690{
691 union
692 {
694 };
695 bool has_;
696
698 {
699 if (not has_)
700 err_.~E();
701 }
702
703public:
705 using error_type = E;
707
708 constexpr expected() noexcept : has_(true) {}
709
710 template <class G>
711 constexpr expected(const unexpected<G> &u) : err_(u.error()), has_(false)
712 {
713 }
714
715 template <class G>
716 constexpr expected(unexpected<G> &&u)
717 : err_(std::move(u).error()), has_(false)
718 {
719 }
720
721 template <class... Args>
722 constexpr explicit expected(unexpect_t, Args &&...args)
723 : err_(std::forward<Args>(args)...), has_(false)
724 {
725 }
726
728 {
729 if (not has_)
730 ::new (static_cast<void *>(std::addressof(err_))) E(o.err_);
731 }
732
733 expected(expected &&o) noexcept(std::is_nothrow_move_constructible_v<E>)
734 : has_(o.has_)
735 {
736 if (not has_)
737 ::new (static_cast<void *>(std::addressof(err_))) E(std::move(o.err_));
738 }
739
741 {
742 if (this != std::addressof(o))
743 {
744 expected tmp(o);
745 destroy();
746 has_ = tmp.has_;
747 if (not has_)
748 ::new (static_cast<void *>(std::addressof(err_))) E(std::move(tmp.err_));
749 }
750 return *this;
751 }
752
754 std::is_nothrow_move_constructible_v<E>)
755 {
756 if (this != std::addressof(o))
757 {
758 expected tmp(std::move(o));
759 destroy();
760 has_ = tmp.has_;
761 if (not has_)
762 ::new (static_cast<void *>(std::addressof(err_))) E(std::move(tmp.err_));
763 }
764 return *this;
765 }
766
768
769 [[nodiscard]] constexpr bool has_value() const noexcept { return has_; }
770 [[nodiscard]] constexpr explicit operator bool() const noexcept { return has_; }
771
772 constexpr void value() const
773 {
774 if (not has_)
776 }
777
778 [[nodiscard]] constexpr const E &error() const & noexcept { return err_; }
779 [[nodiscard]] constexpr E &error() & noexcept { return err_; }
780
781 template <class F>
782 [[nodiscard]] auto and_then(F &&f) const
783 {
785 if (has_)
786 return std::invoke(std::forward<F>(f));
787 return R(unexpected<E>(err_));
788 }
789
790 template <class F>
791 [[nodiscard]] auto or_else(F &&f) const
792 {
794 if (has_)
795 return R();
796 return std::invoke(std::forward<F>(f), err_);
797 }
798};
799
800} // namespace Aleph
801
802#endif // ALEPH_HAS_STD_EXPECTED
803
804#endif // ALEPH_CPP_COMPAT_H
Exception thrown by expected::value() when no value is held.
const char * what() const noexcept override
Get exception description.
E & error() &noexcept
Access the stored error (lvalue).
const E & error() const &noexcept
Access the stored error (const lvalue).
bad_expected_access(E e)
Construct with an error value.
auto and_then(F &&f) const
constexpr expected(unexpect_t, Args &&...args)
constexpr expected() noexcept
constexpr const E & error() const &noexcept
expected & operator=(expected &&o) noexcept(std::is_nothrow_move_constructible_v< E >)
constexpr expected(const unexpected< G > &u)
constexpr E & error() &noexcept
constexpr bool has_value() const noexcept
expected & operator=(const expected &o)
expected(const expected &o)
constexpr expected(unexpected< G > &&u)
constexpr void value() const
expected(expected &&o) noexcept(std::is_nothrow_move_constructible_v< E >)
auto or_else(F &&f) const
Minimal std::expected-style result type for C++20.
auto or_else(F &&f) const &
Monadic error recovery: handle the error.
~expected()
Destructor.
expected & operator=(expected &&o) noexcept(std::is_nothrow_move_constructible_v< T > and std::is_nothrow_move_constructible_v< E >)
Move assignment.
constexpr expected(unexpected< G > &&u)
Construct an error from unexpected (rvalue).
constexpr T & operator*() &noexcept
Access the value (lvalue).
expected & operator=(const expected &o)
Copy assignment.
constexpr T * operator->() noexcept
Access the value via pointer (mutable).
void destroy() noexcept
constexpr T value_or(U &&default_value) const &
Get the value or a default.
constexpr T & value() &
Access the value with exception on error (lvalue).
constexpr E & error() &noexcept
Access the error (lvalue).
constexpr const T & operator*() const &noexcept
Access the value (const lvalue).
expected(const expected &o)
Copy constructor.
expected(expected &&o) noexcept(std::is_nothrow_move_constructible_v< T > and std::is_nothrow_move_constructible_v< E >)
Move constructor.
constexpr bool has_value() const noexcept
Check if a value is held.
auto and_then(F &&f) const &
Monadic bind: chain another fallible operation.
constexpr const E & error() const &noexcept
Access the error (const lvalue).
constexpr expected(unexpect_t, Args &&...args)
Construct an error in place.
constexpr expected()
Default-construct with a value.
auto transform(F &&f) const &
Monadic map: transform the value.
constexpr const T * operator->() const noexcept
Access the value via pointer (const).
constexpr expected(U &&v)
Construct from a value.
constexpr const T & value() const &
Access the value with exception on error (const lvalue).
constexpr expected(const unexpected< G > &u)
Construct an error from unexpected (lvalue).
Wrapper for the error value used to initialize an expected.
constexpr unexpected(Err &&e) noexcept(std::is_nothrow_constructible_v< E, Err >)
Construct the stored error from any value convertible to E.
constexpr E & error() &noexcept
Access the error (lvalue).
constexpr const E & error() const &noexcept
Access the error (const lvalue).
constexpr E && error() &&noexcept
Access the error (rvalue).
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
std::remove_cv_t< std::remove_reference_t< U > > remove_cvref_t
C++17-safe equivalent of C++20 cpp_compat_detail::remove_cvref_t.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
constexpr unexpect_t unexpect
Tag value of type unexpect_t.
STL namespace.
Tag type used to construct an expected holding an error in place.
unexpect_t()=default