aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/std
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/include/std')
-rw-r--r--libstdc++-v3/include/std/algorithm1
-rw-r--r--libstdc++-v3/include/std/array2
-rw-r--r--libstdc++-v3/include/std/atomic14
-rw-r--r--libstdc++-v3/include/std/barrier199
-rw-r--r--libstdc++-v3/include/std/bit31
-rw-r--r--libstdc++-v3/include/std/bitset116
-rw-r--r--libstdc++-v3/include/std/charconv25
-rw-r--r--libstdc++-v3/include/std/chrono385
-rw-r--r--libstdc++-v3/include/std/complex41
-rw-r--r--libstdc++-v3/include/std/concepts25
-rw-r--r--libstdc++-v3/include/std/condition_variable20
-rw-r--r--libstdc++-v3/include/std/debugging77
-rw-r--r--libstdc++-v3/include/std/deque36
-rw-r--r--libstdc++-v3/include/std/expected60
-rw-r--r--libstdc++-v3/include/std/flat_map46
-rw-r--r--libstdc++-v3/include/std/flat_set28
-rw-r--r--libstdc++-v3/include/std/format1604
-rw-r--r--libstdc++-v3/include/std/functional401
-rw-r--r--libstdc++-v3/include/std/future66
-rw-r--r--libstdc++-v3/include/std/generator10
-rw-r--r--libstdc++-v3/include/std/inplace_vector1369
-rw-r--r--libstdc++-v3/include/std/istream13
-rw-r--r--libstdc++-v3/include/std/latch38
-rw-r--r--libstdc++-v3/include/std/limits5
-rw-r--r--libstdc++-v3/include/std/mdspan3399
-rw-r--r--libstdc++-v3/include/std/memory10
-rw-r--r--libstdc++-v3/include/std/mutex24
-rw-r--r--libstdc++-v3/include/std/numeric6
-rw-r--r--libstdc++-v3/include/std/optional599
-rw-r--r--libstdc++-v3/include/std/ostream19
-rw-r--r--libstdc++-v3/include/std/print286
-rw-r--r--libstdc++-v3/include/std/queue103
-rw-r--r--libstdc++-v3/include/std/random3
-rw-r--r--libstdc++-v3/include/std/ranges524
-rw-r--r--libstdc++-v3/include/std/regex1
-rw-r--r--libstdc++-v3/include/std/semaphore31
-rw-r--r--libstdc++-v3/include/std/shared_mutex94
-rw-r--r--libstdc++-v3/include/std/span38
-rw-r--r--libstdc++-v3/include/std/spanstream4
-rw-r--r--libstdc++-v3/include/std/sstream202
-rw-r--r--libstdc++-v3/include/std/stack56
-rw-r--r--libstdc++-v3/include/std/stacktrace54
-rw-r--r--libstdc++-v3/include/std/stop_token26
-rw-r--r--libstdc++-v3/include/std/string21
-rw-r--r--libstdc++-v3/include/std/string_view10
-rw-r--r--libstdc++-v3/include/std/syncstream22
-rw-r--r--libstdc++-v3/include/std/thread66
-rw-r--r--libstdc++-v3/include/std/tuple142
-rw-r--r--libstdc++-v3/include/std/type_traits610
-rw-r--r--libstdc++-v3/include/std/utility93
-rw-r--r--libstdc++-v3/include/std/valarray12
-rw-r--r--libstdc++-v3/include/std/variant36
-rw-r--r--libstdc++-v3/include/std/vector45
53 files changed, 9463 insertions, 1685 deletions
diff --git a/libstdc++-v3/include/std/algorithm b/libstdc++-v3/include/std/algorithm
index 321a5e2..1563cdf 100644
--- a/libstdc++-v3/include/std/algorithm
+++ b/libstdc++-v3/include/std/algorithm
@@ -74,6 +74,7 @@
#define __glibcxx_want_ranges_contains
#define __glibcxx_want_ranges_find_last
#define __glibcxx_want_ranges_fold
+#define __glibcxx_want_ranges_starts_ends_with
#define __glibcxx_want_robust_nonmodifying_seq_ops
#define __glibcxx_want_sample
#define __glibcxx_want_shift
diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array
index fdcf0b0..12f0109 100644
--- a/libstdc++-v3/include/std/array
+++ b/libstdc++-v3/include/std/array
@@ -381,6 +381,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __one.swap(__two); }
#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2766. Swapping non-swappable types
template<typename _Tp, std::size_t _Nm>
__enable_if_t<!__array_traits<_Tp, _Nm>::_Is_swappable::value>
swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&) = delete;
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 9b1aca0..0a510d8 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -217,6 +217,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static_assert(sizeof(_Tp) > 0,
"Incomplete or zero-sized types are not supported");
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4069. std::atomic<volatile T> should be ill-formed
+ static_assert(is_same<_Tp, typename remove_cv<_Tp>::type>::value,
+ "template argument for std::atomic must not be const or volatile");
+
#if __cplusplus > 201703L
static_assert(is_copy_constructible_v<_Tp>);
static_assert(is_move_constructible_v<_Tp>);
@@ -401,21 +406,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void
wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept
{
- std::__atomic_wait_address_v(&_M_i, __old,
- [__m, this] { return this->load(__m); });
+ std::__atomic_wait_address_v(std::addressof(_M_i), __old,
+ [__m, this] { return this->load(__m); });
}
// TODO add const volatile overload
void
notify_one() noexcept
- { std::__atomic_notify_address(&_M_i, false); }
+ { std::__atomic_notify_address(std::addressof(_M_i), false); }
void
notify_all() noexcept
- { std::__atomic_notify_address(&_M_i, true); }
+ { std::__atomic_notify_address(std::addressof(_M_i), true); }
#endif // __cpp_lib_atomic_wait
-
};
/// Partial specialization for pointer types.
diff --git a/libstdc++-v3/include/std/barrier b/libstdc++-v3/include/std/barrier
index 6c3cfd4..56270c9 100644
--- a/libstdc++-v3/include/std/barrier
+++ b/libstdc++-v3/include/std/barrier
@@ -81,105 +81,142 @@ It looks different from literature pseudocode for two main reasons:
enum class __barrier_phase_t : unsigned char { };
- template<typename _CompletionF>
- class __tree_barrier
+ struct __tree_barrier_base
+ {
+ static constexpr ptrdiff_t
+ max() noexcept
+ { return __PTRDIFF_MAX__ - 1; }
+
+ protected:
+ using __atomic_phase_ref_t = std::__atomic_ref<__barrier_phase_t>;
+ using __atomic_phase_const_ref_t = std::__atomic_ref<const __barrier_phase_t>;
+ static constexpr auto __phase_alignment =
+ __atomic_phase_ref_t::required_alignment;
+
+ using __tickets_t = std::array<__barrier_phase_t, 64>;
+ struct alignas(64) /* naturally-align the heap state */ __state_t
{
- using __atomic_phase_ref_t = std::__atomic_ref<__barrier_phase_t>;
- using __atomic_phase_const_ref_t = std::__atomic_ref<const __barrier_phase_t>;
- static constexpr auto __phase_alignment =
- __atomic_phase_ref_t::required_alignment;
+ alignas(__phase_alignment) __tickets_t __tickets;
+ };
- using __tickets_t = std::array<__barrier_phase_t, 64>;
- struct alignas(64) /* naturally-align the heap state */ __state_t
- {
- alignas(__phase_alignment) __tickets_t __tickets;
- };
+ ptrdiff_t _M_expected;
+ __atomic_base<__state_t*> _M_state{nullptr};
+ __atomic_base<ptrdiff_t> _M_expected_adjustment{0};
+ alignas(__phase_alignment) __barrier_phase_t _M_phase{};
- ptrdiff_t _M_expected;
- unique_ptr<__state_t[]> _M_state;
- __atomic_base<ptrdiff_t> _M_expected_adjustment;
- _CompletionF _M_completion;
+ explicit constexpr
+ __tree_barrier_base(ptrdiff_t __expected)
+ : _M_expected(__expected)
+ {
+ __glibcxx_assert(__expected >= 0 && __expected <= max());
- alignas(__phase_alignment) __barrier_phase_t _M_phase;
+ if (!std::is_constant_evaluated())
+ _M_state.store(_M_alloc_state().release(), memory_order_release);
+ }
- bool
- _M_arrive(__barrier_phase_t __old_phase, size_t __current)
- {
- const auto __old_phase_val = static_cast<unsigned char>(__old_phase);
- const auto __half_step =
- static_cast<__barrier_phase_t>(__old_phase_val + 1);
- const auto __full_step =
- static_cast<__barrier_phase_t>(__old_phase_val + 2);
+ unique_ptr<__state_t[]>
+ _M_alloc_state()
+ {
+ size_t const __count = (_M_expected + 1) >> 1;
+ return std::make_unique<__state_t[]>(__count);
+ }
- size_t __current_expected = _M_expected;
- __current %= ((_M_expected + 1) >> 1);
+ bool
+ _M_arrive(__barrier_phase_t __old_phase, size_t __current)
+ {
+ const auto __old_phase_val = static_cast<unsigned char>(__old_phase);
+ const auto __half_step =
+ static_cast<__barrier_phase_t>(__old_phase_val + 1);
+ const auto __full_step =
+ static_cast<__barrier_phase_t>(__old_phase_val + 2);
+
+ size_t __current_expected = _M_expected;
+ __current %= ((_M_expected + 1) >> 1);
+
+ __state_t* const __state = _M_state.load(memory_order_relaxed);
+
+ for (int __round = 0; ; ++__round)
+ {
+ if (__current_expected <= 1)
+ return true;
+ size_t const __end_node = ((__current_expected + 1) >> 1),
+ __last_node = __end_node - 1;
+ for ( ; ; ++__current)
+ {
+ if (__current == __end_node)
+ __current = 0;
+ auto __expect = __old_phase;
+ __atomic_phase_ref_t __phase(__state[__current]
+ .__tickets[__round]);
+ if (__current == __last_node && (__current_expected & 1))
+ {
+ if (__phase.compare_exchange_strong(__expect, __full_step,
+ memory_order_acq_rel))
+ break; // I'm 1 in 1, go to next __round
+ }
+ else if (__phase.compare_exchange_strong(__expect, __half_step,
+ memory_order_acq_rel))
+ {
+ return false; // I'm 1 in 2, done with arrival
+ }
+ else if (__expect == __half_step)
+ {
+ if (__phase.compare_exchange_strong(__expect, __full_step,
+ memory_order_acq_rel))
+ break; // I'm 2 in 2, go to next __round
+ }
+ }
+ __current_expected = __last_node + 1;
+ __current >>= 1;
+ }
+ }
+ };
- for (int __round = 0; ; ++__round)
- {
- if (__current_expected <= 1)
- return true;
- size_t const __end_node = ((__current_expected + 1) >> 1),
- __last_node = __end_node - 1;
- for ( ; ; ++__current)
- {
- if (__current == __end_node)
- __current = 0;
- auto __expect = __old_phase;
- __atomic_phase_ref_t __phase(_M_state[__current]
- .__tickets[__round]);
- if (__current == __last_node && (__current_expected & 1))
- {
- if (__phase.compare_exchange_strong(__expect, __full_step,
- memory_order_acq_rel))
- break; // I'm 1 in 1, go to next __round
- }
- else if (__phase.compare_exchange_strong(__expect, __half_step,
- memory_order_acq_rel))
- {
- return false; // I'm 1 in 2, done with arrival
- }
- else if (__expect == __half_step)
- {
- if (__phase.compare_exchange_strong(__expect, __full_step,
- memory_order_acq_rel))
- break; // I'm 2 in 2, go to next __round
- }
- }
- __current_expected = __last_node + 1;
- __current >>= 1;
- }
- }
+ template<typename _CompletionF>
+ class __tree_barrier : public __tree_barrier_base
+ {
+ [[no_unique_address]] _CompletionF _M_completion;
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3898. Possibly unintended preconditions for completion functions
+ void _M_invoke_completion() noexcept { _M_completion(); }
public:
using arrival_token = __barrier_phase_t;
- static constexpr ptrdiff_t
- max() noexcept
- { return __PTRDIFF_MAX__; }
-
+ constexpr
__tree_barrier(ptrdiff_t __expected, _CompletionF __completion)
- : _M_expected(__expected), _M_expected_adjustment(0),
- _M_completion(move(__completion)),
- _M_phase(static_cast<__barrier_phase_t>(0))
- {
- size_t const __count = (_M_expected + 1) >> 1;
-
- _M_state = std::make_unique<__state_t[]>(__count);
- }
+ : __tree_barrier_base(__expected), _M_completion(std::move(__completion))
+ { }
[[nodiscard]] arrival_token
arrive(ptrdiff_t __update)
{
+ __glibcxx_assert(__update > 0);
+ // FIXME: Check that update is less than or equal to the expected count
+ // for the current barrier phase.
+
std::hash<std::thread::id> __hasher;
size_t __current = __hasher(std::this_thread::get_id());
__atomic_phase_ref_t __phase(_M_phase);
const auto __old_phase = __phase.load(memory_order_relaxed);
const auto __cur = static_cast<unsigned char>(__old_phase);
- for(; __update; --__update)
+
+ if (__cur == 0 && !_M_state.load(memory_order_relaxed)) [[unlikely]]
+ {
+ auto __p = _M_alloc_state();
+ __state_t* __val = nullptr;
+ if (_M_state.compare_exchange_strong(__val, __p.get(),
+ memory_order_seq_cst,
+ memory_order_acquire))
+ __p.release();
+ }
+
+ for (; __update; --__update)
{
- if(_M_arrive(__old_phase, __current))
+ if (_M_arrive(__old_phase, __current))
{
- _M_completion();
+ _M_invoke_completion();
_M_expected += _M_expected_adjustment.load(memory_order_relaxed);
_M_expected_adjustment.store(0, memory_order_relaxed);
auto __new_phase = static_cast<__barrier_phase_t>(__cur + 2);
@@ -194,11 +231,7 @@ It looks different from literature pseudocode for two main reasons:
wait(arrival_token&& __old_phase) const
{
__atomic_phase_const_ref_t __phase(_M_phase);
- auto const __test_fn = [=]
- {
- return __phase.load(memory_order_acquire) != __old_phase;
- };
- std::__atomic_wait_address(&_M_phase, __test_fn);
+ __phase.wait(__old_phase, memory_order_acquire);
}
void
@@ -212,6 +245,8 @@ It looks different from literature pseudocode for two main reasons:
template<typename _CompletionF = __empty_completion>
class barrier
{
+ static_assert(is_invocable_v<_CompletionF&>);
+
// Note, we may introduce a "central" barrier algorithm at some point
// for more space constrained targets
using __algorithm_t = __tree_barrier<_CompletionF>;
@@ -236,7 +271,7 @@ It looks different from literature pseudocode for two main reasons:
max() noexcept
{ return __algorithm_t::max(); }
- explicit
+ constexpr explicit
barrier(ptrdiff_t __count, _CompletionF __completion = _CompletionF())
: _M_b(__count, std::move(__completion))
{ }
diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit
index a481781..fd75edf 100644
--- a/libstdc++-v3/include/std/bit
+++ b/libstdc++-v3/include/std/bit
@@ -153,18 +153,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif // __cpp_lib_byteswap
/// @cond undocumented
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
template<typename _Tp>
constexpr _Tp
__rotl(_Tp __x, int __s) noexcept
{
constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
- if _GLIBCXX17_CONSTEXPR ((_Nd & (_Nd - 1)) == 0)
+ if constexpr ((_Nd & (_Nd - 1)) == 0)
{
// Variant for power of two _Nd which the compiler can
// easily pattern match.
constexpr unsigned __uNd = _Nd;
- const unsigned __r = __s;
+ const auto __r = static_cast<unsigned>(__s);
return (__x << (__r % __uNd)) | (__x >> ((-__r) % __uNd));
}
const int __r = __s % _Nd;
@@ -181,12 +183,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__rotr(_Tp __x, int __s) noexcept
{
constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
- if _GLIBCXX17_CONSTEXPR ((_Nd & (_Nd - 1)) == 0)
+ if constexpr ((_Nd & (_Nd - 1)) == 0)
{
// Variant for power of two _Nd which the compiler can
// easily pattern match.
constexpr unsigned __uNd = _Nd;
- const unsigned __r = __s;
+ const auto __r = static_cast<unsigned>(__s);
return (__x >> (__r % __uNd)) | (__x << ((-__r) % __uNd));
}
const int __r = __s % _Nd;
@@ -215,17 +217,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr auto _Nd_ul = __int_traits<unsigned long>::__digits;
constexpr auto _Nd_u = __int_traits<unsigned>::__digits;
- if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u)
+ if constexpr (_Nd <= _Nd_u)
{
constexpr int __diff = _Nd_u - _Nd;
return __builtin_clz(__x) - __diff;
}
- else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ul)
+ else if constexpr (_Nd <= _Nd_ul)
{
constexpr int __diff = _Nd_ul - _Nd;
return __builtin_clzl(__x) - __diff;
}
- else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ull)
+ else if constexpr (_Nd <= _Nd_ull)
{
constexpr int __diff = _Nd_ull - _Nd;
return __builtin_clzll(__x) - __diff;
@@ -272,11 +274,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr auto _Nd_ul = __int_traits<unsigned long>::__digits;
constexpr auto _Nd_u = __int_traits<unsigned>::__digits;
- if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u)
+ if constexpr (_Nd <= _Nd_u)
return __builtin_ctz(__x);
- else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ul)
+ else if constexpr (_Nd <= _Nd_ul)
return __builtin_ctzl(__x);
- else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ull)
+ else if constexpr (_Nd <= _Nd_ull)
return __builtin_ctzll(__x);
else // (_Nd > _Nd_ull)
{
@@ -314,11 +316,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr auto _Nd_ul = __int_traits<unsigned long>::__digits;
constexpr auto _Nd_u = __int_traits<unsigned>::__digits;
- if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u)
+ if constexpr (_Nd <= _Nd_u)
return __builtin_popcount(__x);
- else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ul)
+ else if constexpr (_Nd <= _Nd_ul)
return __builtin_popcountl(__x);
- else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ull)
+ else if constexpr (_Nd <= _Nd_ull)
return __builtin_popcountll(__x);
else // (_Nd > _Nd_ull)
{
@@ -357,7 +359,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
using __promoted_type = decltype(__x << 1);
- if _GLIBCXX17_CONSTEXPR (!is_same<__promoted_type, _Tp>::value)
+ if constexpr (!is_same<__promoted_type, _Tp>::value)
{
// If __x undergoes integral promotion then shifting by _Nd is
// not undefined. In order to make the shift undefined, so that
@@ -388,6 +390,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return _Nd - std::__countl_zero(__x);
}
+#pragma GCC diagnostic pop
/// @endcond
#ifdef __cpp_lib_bitops // C++ >= 20
diff --git a/libstdc++-v3/include/std/bitset b/libstdc++-v3/include/std/bitset
index c07117a..ece3593 100644
--- a/libstdc++-v3/include/std/bitset
+++ b/libstdc++-v3/include/std/bitset
@@ -61,8 +61,13 @@
#endif
#define __glibcxx_want_constexpr_bitset
+#define __glibcxx_want_bitset // ...construct from string_view
#include <bits/version.h>
+#ifdef __cpp_lib_bitset // ...construct from string_view
+# include <string_view>
+#endif
+
#define _GLIBCXX_BITSET_BITS_PER_WORD (__CHAR_BIT__ * __SIZEOF_LONG__)
#define _GLIBCXX_BITSET_WORDS(__n) \
((__n) / _GLIBCXX_BITSET_BITS_PER_WORD + \
@@ -715,7 +720,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
namespace __bitset
{
-#if _GLIBCXX_HOSTED
+#ifdef __cpp_lib_bitset // ...construct from string_view
+ template<typename _CharT>
+ using __string = std::basic_string_view<_CharT>;
+#elif _GLIBCXX_HOSTED
template<typename _CharT>
using __string = std::basic_string<_CharT>;
#else
@@ -752,7 +760,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
* (Note that %bitset does @e not meet the formal requirements of a
* <a href="tables.html#65">container</a>. Mainly, it lacks iterators.)
*
- * The template argument, @a Nb, may be any non-negative number,
+ * The template argument, `Nb`, may be any non-negative number,
* specifying the number of bits (e.g., "0", "12", "1024*1024").
*
* In the general unoptimized case, storage is allocated in word-sized
@@ -816,28 +824,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
typedef _Base_bitset<_GLIBCXX_BITSET_WORDS(_Nb)> _Base;
typedef unsigned long _WordT;
-#if _GLIBCXX_HOSTED
- template<class _CharT, class _Traits, class _Alloc>
- _GLIBCXX23_CONSTEXPR
- void
- _M_check_initial_position(const std::basic_string<_CharT, _Traits, _Alloc>& __s,
- size_t __position) const
+ template<class _Str>
+ _GLIBCXX23_CONSTEXPR void
+ _M_check_initial_position(
+ const _Str& __s, typename _Str::size_type __position) const
{
if (__position > __s.size())
- __throw_out_of_range_fmt(__N("bitset::bitset: __position "
- "(which is %zu) > __s.size() "
- "(which is %zu)"),
- __position, __s.size());
+ __throw_out_of_range_fmt(
+ __N("bitset::bitset:"
+ " __position (which is %zu) > __s.size() (which is %zu)"),
+ size_t(__position), size_t(__s.size()));
}
-#endif // HOSTED
_GLIBCXX23_CONSTEXPR
void _M_check(size_t __position, const char *__s) const
{
if (__position >= _Nb)
- __throw_out_of_range_fmt(__N("%s: __position (which is %zu) "
- ">= _Nb (which is %zu)"),
- __s, __position, _Nb);
+ __throw_out_of_range_fmt(
+ __N("%s: __position (which is %zu) >= _Nb (which is %zu)"),
+ __s, size_t(__position), size_t(_Nb));
}
_GLIBCXX23_CONSTEXPR
@@ -954,12 +959,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
#if _GLIBCXX_HOSTED
/**
* Use a subset of a string.
- * @param __s A string of @a 0 and @a 1 characters.
- * @param __position Index of the first character in @a __s to use;
+ * @param __s A string of `0` and `1` characters.
+ * @param __position Index of the first character in `__s` to use;
* defaults to zero.
- * @throw std::out_of_range If @a pos is bigger the size of @a __s.
+ * @throw std::out_of_range If `__position > __s.size()`.
* @throw std::invalid_argument If a character appears in the string
- * which is neither @a 0 nor @a 1.
+ * which is neither `0` nor `1`.
*/
template<class _CharT, class _Traits, class _Alloc>
_GLIBCXX23_CONSTEXPR
@@ -976,13 +981,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
/**
* Use a subset of a string.
- * @param __s A string of @a 0 and @a 1 characters.
- * @param __position Index of the first character in @a __s to use.
+ * @param __s A string of `0` and `1` characters.
+ * @param __position Index of the first character in `__s` to use.
* @param __n The number of characters to copy.
- * @throw std::out_of_range If @a __position is bigger the size
- * of @a __s.
+ * @throw std::out_of_range If `__position > __s.size()`.
* @throw std::invalid_argument If a character appears in the string
- * which is neither @a 0 nor @a 1.
+ * which is neither `0` nor `1`.
*/
template<class _CharT, class _Traits, class _Alloc>
_GLIBCXX23_CONSTEXPR
@@ -1008,17 +1012,50 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
}
#endif // HOSTED
+#ifdef __cpp_lib_bitset // C++ >= 23
+ /**
+ * Use a subset of a string view.
+ * @param __s A `string_view` of a sequence of `0` and `1` characters.
+ * @param __position Index of the first character in `__s` to use.
+ * @param __n The maximum number of characters from `__s` to use.
+ * @param __zero The character corresponding to the value 0.
+ * @param __one The character corresponding to the value 1.
+ * @throw std::out_of_range If `__position > __s.size()`.
+ * @throw std::invalid_argument If a character appears in `__s`
+ * which is neither `0` nor `1`.
+ */
+ template<class _CharT, class _Traits>
+ constexpr explicit
+ bitset(basic_string_view<_CharT, _Traits> __s,
+ basic_string_view<_CharT, _Traits>::size_type __position = 0,
+ basic_string_view<_CharT, _Traits>::size_type __n =
+ basic_string_view<_CharT, _Traits>::npos,
+ _CharT __zero = _CharT('0'), _CharT __one = _CharT('1'))
+ : _Base()
+ {
+ _M_check_initial_position(__s, __position);
+ _M_copy_from_ptr<_CharT, _Traits>(
+ __s.data(), __s.size(), __position, __n, __zero, __one);
+ }
+#endif
+
#if __cplusplus >= 201103L
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4294. bitset(const CharT*) constructor needs to be constrained
/**
* Construct from a character %array.
- * @param __str An %array of characters @a zero and @a one.
+ * @param __str An %array of characters `__zero` and `__one`.
* @param __n The number of characters to use.
* @param __zero The character corresponding to the value 0.
* @param __one The character corresponding to the value 1.
* @throw std::invalid_argument If a character appears in the string
- * which is neither @a __zero nor @a __one.
+ * which is neither `__zero` nor `__one`.
*/
- template<typename _CharT>
+ template<typename _CharT,
+ typename = _Require<is_trivially_copyable<_CharT>,
+ is_standard_layout<_CharT>,
+ is_trivially_default_constructible<_CharT>,
+ __not_<is_array<_CharT>>>>
[[__gnu__::__nonnull__]]
_GLIBCXX23_CONSTEXPR
explicit
@@ -1028,10 +1065,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_CharT __zero = _CharT('0'), _CharT __one = _CharT('1'))
: _Base()
{
-#if _GLIBCXX_HOSTED
if (!__str)
__throw_logic_error(__N("bitset::bitset(const _CharT*, ...)"));
-#endif
using _Traits = typename __bitset::__string<_CharT>::traits_type;
if (__n == __bitset::__string<_CharT>::npos)
@@ -1514,7 +1549,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
size_t __pos, size_t __n, _CharT __zero, _CharT __one)
{
reset();
- const size_t __nbits = std::min(_Nb, std::min(__n, size_t(__len - __pos)));
+ const size_t __rlen = std::min(__n, size_t(__len - __pos));
+ const size_t __nbits = std::min(_Nb, __rlen);
+ for (size_t __i = __rlen - __nbits; __i > 0; --__i)
+ {
+ const _CharT __c = __s[__pos + __rlen - __i];
+ if (!_Traits::eq(__c, __zero) && !_Traits::eq(__c, __one))
+ __throw_invalid_argument(__N("bitset::_M_copy_from_ptr"));
+ }
for (size_t __i = __nbits; __i > 0; --__i)
{
const _CharT __c = __s[__pos + __nbits - __i];
@@ -1605,6 +1647,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
typedef std::basic_istream<_CharT, _Traits> __istream_type;
typedef typename __istream_type::ios_base __ios_base;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
struct _Buffer
{
static _GLIBCXX_CONSTEXPR bool _S_use_alloca() { return _Nb <= 256; }
@@ -1613,18 +1657,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
~_Buffer()
{
- if _GLIBCXX17_CONSTEXPR (!_S_use_alloca())
+ if _GLIBCXX_CONSTEXPR (!_S_use_alloca())
delete[] _M_ptr;
}
_CharT* const _M_ptr;
};
_CharT* __ptr;
- if _GLIBCXX17_CONSTEXPR (_Buffer::_S_use_alloca())
+ if _GLIBCXX_CONSTEXPR (_Buffer::_S_use_alloca())
__ptr = (_CharT*)__builtin_alloca(_Nb);
else
__ptr = new _CharT[_Nb];
const _Buffer __buf(__ptr);
+#pragma GCC diagnostic pop
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 303. Bitset input operator underspecified
@@ -1673,7 +1718,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{ __is._M_setstate(__ios_base::badbit); }
}
- if _GLIBCXX17_CONSTEXPR (_Nb)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
+ if _GLIBCXX_CONSTEXPR (_Nb)
{
if (size_t __len = __ptr - __buf._M_ptr)
__x.template _M_copy_from_ptr<_CharT, _Traits>(__buf._M_ptr, __len,
@@ -1682,6 +1729,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
else
__state |= __ios_base::failbit;
}
+#pragma GCC diagnostic pop
if (__state)
__is.setstate(__state);
return __is;
diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv
index 75fcb71..47f5aaa 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -35,6 +35,7 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" // __int128
+#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
#include <bits/requires_hosted.h> // for error codes
@@ -239,7 +240,7 @@ namespace __detail
to_chars_result __res;
unsigned __len = 0;
- if _GLIBCXX17_CONSTEXPR (__gnu_cxx::__int_traits<_Tp>::__digits <= 16)
+ if constexpr (__gnu_cxx::__int_traits<_Tp>::__digits <= 16)
{
__len = __val > 077777u ? 6u
: __val > 07777u ? 5u
@@ -336,7 +337,7 @@ namespace __detail
*__first = '0';
return { __first + 1, errc{} };
}
- else if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value)
+ else if constexpr (std::is_signed<_Tp>::value)
if (__value < 0)
{
*__first++ = '-';
@@ -389,6 +390,10 @@ _GLIBCXX_TO_CHARS(unsigned __GLIBCXX_TYPE_INT_N_2)
_GLIBCXX_TO_CHARS(signed __GLIBCXX_TYPE_INT_N_3)
_GLIBCXX_TO_CHARS(unsigned __GLIBCXX_TYPE_INT_N_3)
#endif
+#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
+_GLIBCXX_TO_CHARS(signed __int128)
+_GLIBCXX_TO_CHARS(unsigned __int128)
+#endif
#undef _GLIBCXX_TO_CHARS
// _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -452,7 +457,7 @@ namespace __detail
_GLIBCXX20_CONSTEXPR unsigned char
__from_chars_alnum_to_val(unsigned char __c)
{
- if _GLIBCXX17_CONSTEXPR (_DecOnly)
+ if constexpr (_DecOnly)
return static_cast<unsigned char>(__c - '0');
else
return __from_chars_alnum_to_val_table<_DecOnly>::value.__data[__c];
@@ -549,10 +554,10 @@ namespace __detail
} // namespace __detail
- /// std::from_chars for integral types.
+ /// std::from_chars for integer types.
template<typename _Tp,
- enable_if_t<__or_<__is_standard_integer<_Tp>,
- is_same<char, remove_cv_t<_Tp>>>::value, int> = 0>
+ enable_if_t<__or_<__is_signed_or_unsigned_integer<_Tp>,
+ is_same<char, _Tp>>::value, int> = 0>
_GLIBCXX23_CONSTEXPR from_chars_result
from_chars(const char* __first, const char* __last, _Tp& __value,
int __base = 10)
@@ -562,7 +567,7 @@ namespace __detail
from_chars_result __res{__first, {}};
int __sign = 1;
- if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value)
+ if constexpr (std::is_signed<_Tp>::value)
if (__first != __last && *__first == '-')
{
__sign = -1;
@@ -595,7 +600,7 @@ namespace __detail
__res.ec = errc::result_out_of_range;
else
{
- if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value)
+ if constexpr (std::is_signed<_Tp>::value)
{
_Tp __tmp;
if (__builtin_mul_overflow(__val, __sign, &__tmp))
@@ -605,8 +610,8 @@ namespace __detail
}
else
{
- if _GLIBCXX17_CONSTEXPR (__gnu_cxx::__int_traits<_Up>::__max
- > __gnu_cxx::__int_traits<_Tp>::__max)
+ if constexpr (__gnu_cxx::__int_traits<_Up>::__max
+ > __gnu_cxx::__int_traits<_Tp>::__max)
{
if (__val > __gnu_cxx::__int_traits<_Tp>::__max)
__res.ec = errc::result_out_of_range;
diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono
index 8eb9fd9..3e0cf42e 100644
--- a/libstdc++-v3/include/std/chrono
+++ b/libstdc++-v3/include/std/chrono
@@ -22,6 +22,8 @@
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
+// [time]
+
/** @file include/chrono
* This is a Standard C++ Library header.
* @ingroup chrono
@@ -42,23 +44,29 @@
# include <bits/c++0x_warning.h>
#else
+#define __glibcxx_want_chrono
+#define __glibcxx_want_chrono_udls
+#include <bits/version.h>
+
#include <bits/chrono.h>
-#if __cplusplus >= 202002L
+#if __cpp_lib_bitops >= 201907L
# include <bit> // __countr_zero
#endif
-#if __cplusplus >= 202002L && _GLIBCXX_HOSTED
+#ifdef __glibcxx_chrono_cxx20
+# include <bits/stl_algo.h> // upper_bound
+# include <bits/range_access.h> // begin/end for arrays
+#endif
+#if __cpp_lib_chrono >= 201803L // C++20 && HOSTED && USE_CXX11_ABI
# include <sstream>
# include <string>
# include <vector>
-# include <bits/stl_algo.h> // upper_bound
# include <bits/shared_ptr.h>
# include <bits/unique_ptr.h>
#endif
-
-#define __glibcxx_want_chrono
-#define __glibcxx_want_chrono_udls
-#include <bits/version.h>
+#if __glibcxx_chrono_cxx20 >= 202306L // C++26
+# include <bits/functional_hash.h>
+#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -79,7 +87,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*/
namespace chrono
{
-#if __cplusplus >= 202002L
+#ifdef __glibcxx_chrono_cxx20
/// @addtogroup chrono
/// @{
struct local_t { };
@@ -175,13 +183,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using period = system_clock::period;
using duration = chrono::duration<rep, period>;
using time_point = chrono::time_point<tai_clock>;
- static constexpr bool is_steady = false; // XXX true for CLOCK_TAI?
+ static constexpr bool is_steady = false;
- // TODO move into lib, use CLOCK_TAI on linux, add extension point.
[[nodiscard]]
static time_point
- now()
- { return from_utc(utc_clock::now()); }
+ now(); // in src/c++20/clock.cc
template<typename _Duration>
[[nodiscard]]
@@ -215,13 +221,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using period = system_clock::period;
using duration = chrono::duration<rep, period>;
using time_point = chrono::time_point<gps_clock>;
- static constexpr bool is_steady = false; // XXX
+ static constexpr bool is_steady = false;
- // TODO move into lib, add extension point.
[[nodiscard]]
static time_point
- now()
- { return from_utc(utc_clock::now()); }
+ now(); // in src/c++20/clock.cc
template<typename _Duration>
[[nodiscard]]
@@ -2305,8 +2309,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__r *= 10;
return __r;
}
-
- template<typename _Duration> struct __utc_leap_second;
}
/// @endcond
@@ -2481,30 +2483,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__byte_duration<ratio<1>> _M_s{};
bool _M_is_neg{};
__subseconds<precision> _M_ss{};
-
- template<typename> friend struct __detail::__utc_leap_second;
};
- /// @cond undocumented
- namespace __detail
- {
- // Represents a time that is within a leap second insertion.
- template<typename _Duration>
- struct __utc_leap_second
- {
- explicit
- __utc_leap_second(const sys_time<_Duration>& __s)
- : _M_date(chrono::floor<days>(__s)), _M_time(__s - _M_date)
- {
- ++_M_time._M_s;
- }
-
- sys_days _M_date;
- hh_mm_ss<common_type_t<_Duration, days>> _M_time;
- };
- }
- /// @endcond
-
// 12/24 HOURS FUNCTIONS
constexpr bool
@@ -3345,7 +3325,328 @@ namespace __detail
#endif // C++20
} // namespace chrono
-#if __cplusplus >= 202002L
+#if __glibcxx_chrono_cxx20 >= 202306 // C++26
+ // Hash support [time.hash]
+
+ template<typename _Tp>
+ concept __is_nothrow_copy_hashable = requires(const _Tp& __t) {
+ { hash<_Tp>{}(_Tp(__t)) } noexcept -> same_as<size_t>;
+ };
+
+ namespace chrono {
+
+ template<typename _T1, typename... _Ts>
+ [[__gnu__::__always_inline__]]
+ constexpr auto
+ __pack_ints(_T1 __v1, _Ts... __vs)
+ {
+ using _ResT = decltype([] {
+ constexpr size_t __tsize = (sizeof(_T1) + ... + sizeof(_Ts));
+ if constexpr (__tsize <= 1)
+ return static_cast<unsigned char>(0);
+ else if constexpr (__tsize <= 2)
+ return static_cast<__UINT16_TYPE__>(0);
+ else if constexpr (__tsize <= 4)
+ return static_cast<__UINT32_TYPE__>(0);
+ else if constexpr (__tsize <= 8)
+ return static_cast<__UINT64_TYPE__>(0);
+ else
+ static_assert(__tsize <= 8);
+ }());
+
+ _ResT __res = __v1;
+ ((__res = (__res << (sizeof(_Ts) * __CHAR_BIT__) | _ResT(__vs))), ...);
+ return __res;
+ }
+
+ template<typename _Tp>
+ [[__gnu__::__always_inline__]]
+ constexpr auto
+ __as_int(_Tp __val)
+ {
+ if constexpr (is_same_v<_Tp, year>)
+ return static_cast<unsigned short>(static_cast<int>(__val));
+ else if constexpr (is_same_v<_Tp, month> || is_same_v<_Tp, day>)
+ return static_cast<unsigned char>(static_cast<unsigned>(__val));
+ else if constexpr (is_same_v<_Tp, weekday>)
+ return static_cast<unsigned char>(__val.c_encoding());
+ else if constexpr (is_same_v<_Tp, weekday_indexed>)
+ return __pack_ints(chrono::__as_int(__val.weekday()),
+ static_cast<unsigned char>(__val.index()));
+ else if constexpr (is_same_v<_Tp, weekday_last>)
+ return chrono::__as_int(__val.weekday());
+ else
+ static_assert(false);
+ }
+
+ template<typename _Arg, typename... _Args>
+ size_t
+ __int_hash(_Arg __arg, _Args... __args)
+ {
+ static_assert((is_integral_v<_Arg> && ... && is_integral_v<_Args>));
+
+ // TODO consider using a better quality hasher
+ using _Hasher = _Hash_impl;
+ size_t __result = _Hasher::hash(__arg);
+ ((__result = _Hasher::__hash_combine(__args, __result)), ...);
+ return __result;
+ }
+
+ template<typename... _Tps>
+ [[__gnu__::__always_inline__]]
+ inline size_t
+ __hash(_Tps... __vals)
+ {
+ if constexpr (sizeof...(_Tps) == 1)
+ return chrono::__int_hash(chrono::__as_int(__vals)...);
+ else
+ {
+ auto __res = chrono::__pack_ints(chrono::__as_int(__vals)...);
+ return chrono::__int_hash(__res);
+ }
+ }
+ } // namespace chrono
+
+ // duration
+ template<typename _Rep, typename _Period>
+ requires __is_hash_enabled_for<_Rep>
+ struct hash<chrono::duration<_Rep, _Period>>
+ {
+ size_t
+ operator()(const chrono::duration<_Rep, _Period>& __val) const
+ noexcept(__is_nothrow_copy_hashable<_Rep>)
+ {
+ if constexpr (is_integral_v<_Rep>)
+ return chrono::__int_hash(__val.count());
+ else
+ return hash<_Rep>{}(__val.count());
+ }
+ };
+
+ template<typename _Rep, typename _Period>
+ struct __is_fast_hash<hash<chrono::duration<_Rep, _Period>>>
+ : __is_fast_hash<hash<_Rep>>
+ {};
+
+ // time_point
+ template<typename _Clock, typename _Dur>
+ requires __is_hash_enabled_for<_Dur>
+ struct hash<chrono::time_point<_Clock, _Dur>>
+ {
+ size_t
+ operator()(const chrono::time_point<_Clock, _Dur>& __val) const
+ noexcept(__is_nothrow_copy_hashable<_Dur>)
+ { return hash<_Dur>{}(__val.time_since_epoch()); }
+ };
+
+ template<typename _Clock, typename _Dur>
+ struct __is_fast_hash<hash<chrono::time_point<_Clock, _Dur>>>
+ : __is_fast_hash<hash<_Dur>>
+ {};
+
+ // day
+ template<>
+ struct hash<chrono::day>
+ {
+ size_t
+ operator()(chrono::day __val) const noexcept
+ { return chrono::__hash(__val); }
+ };
+
+ // month
+ template<>
+ struct hash<chrono::month>
+ {
+ size_t
+ operator()(chrono::month __val) const noexcept
+ { return chrono::__hash(__val); }
+ };
+
+ // year
+ template<>
+ struct hash<chrono::year>
+ {
+ size_t
+ operator()(chrono::year __val) const noexcept
+ { return chrono::__hash(__val); }
+ };
+
+ // weekday
+ template<>
+ struct hash<chrono::weekday>
+ {
+ size_t
+ operator()(chrono::weekday __val) const noexcept
+ { return chrono::__hash(__val); }
+ };
+
+ // weekday_indexed
+ template<>
+ struct hash<chrono::weekday_indexed>
+ {
+ size_t
+ operator()(chrono::weekday_indexed __val) const noexcept
+ { return chrono::__hash(__val); }
+ };
+
+ // weekday_last
+ template<>
+ struct hash<chrono::weekday_last>
+ {
+ size_t
+ operator()(chrono::weekday_last __val) const noexcept
+ { return chrono::__hash(__val); }
+ };
+
+ // month_day
+ template<>
+ struct hash<chrono::month_day>
+ {
+ size_t
+ operator()(chrono::month_day __val) const noexcept
+ { return chrono::__hash(__val.month(), __val.day()); }
+ };
+
+ // month_day_last
+ template<>
+ struct hash<chrono::month_day_last>
+ {
+ size_t operator()(chrono::month_day_last __val) const noexcept
+ { return chrono::__hash(__val.month()); }
+ };
+
+ // month_weekday
+ template<>
+ struct hash<chrono::month_weekday>
+ {
+ size_t
+ operator()(chrono::month_weekday __val) const noexcept
+ { return chrono::__hash(__val.month(), __val.weekday_indexed()); }
+ };
+
+ // month_weekday_last
+ template<>
+ struct hash<chrono::month_weekday_last>
+ {
+ size_t
+ operator()(chrono::month_weekday_last __val) const noexcept
+ { return chrono::__hash(__val.month(), __val.weekday_last()); }
+ };
+
+ // year_month
+ template<>
+ struct hash<chrono::year_month>
+ {
+ size_t
+ operator()(chrono::year_month __val) const noexcept
+ { return chrono::__hash(__val.year(), __val.month()); }
+ };
+
+ // year_month_day
+ template<>
+ struct hash<chrono::year_month_day>
+ {
+ size_t
+ operator()(chrono::year_month_day __val) const noexcept
+ { return chrono::__hash(__val.year(), __val.month(), __val.day()); }
+ };
+
+ // year_month_day_last
+ template<>
+ struct hash<chrono::year_month_day_last>
+ {
+ size_t
+ operator()(chrono::year_month_day_last __val) const noexcept
+ { return chrono::__hash(__val.year(), __val.month()); }
+ };
+
+ // year_month_weekday
+ template<>
+ struct hash<chrono::year_month_weekday>
+ {
+ size_t
+ operator()(chrono::year_month_weekday __val) const noexcept
+ {
+ return chrono::__hash(__val.year(), __val.month(),
+ __val.weekday_indexed());
+ }
+ };
+
+ // year_month_weekday_last
+ template<>
+ struct hash<chrono::year_month_weekday_last>
+ {
+ size_t
+ operator()(chrono::year_month_weekday_last __val) const noexcept
+ {
+ return chrono::__hash(__val.year(), __val.month(),
+ __val.weekday_last());
+ }
+ };
+
+#if _GLIBCXX_HOSTED
+#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
+ // zoned_time
+ template<typename _Duration, typename _TimeZonePtr>
+ requires __is_hash_enabled_for<
+ typename chrono::zoned_time<_Duration, _TimeZonePtr>::duration>
+ && __is_hash_enabled_for<_TimeZonePtr>
+ struct hash<chrono::zoned_time<_Duration, _TimeZonePtr>>
+ {
+ private:
+ using _ActualDuration =
+ typename chrono::zoned_time<_Duration, _TimeZonePtr>::duration;
+
+ public:
+ size_t
+ operator()(const chrono::zoned_time<_Duration, _TimeZonePtr>& __val) const
+ noexcept(__is_nothrow_copy_hashable<_ActualDuration>
+ && __is_nothrow_copy_hashable<_TimeZonePtr>)
+ {
+ const auto __iduration = [&] {
+ const _ActualDuration __sd = __val.get_sys_time().time_since_epoch();
+ if constexpr (is_integral_v<typename _ActualDuration::rep>)
+ return __sd.count();
+ else
+ return hash<_ActualDuration>{}(__sd);
+ }();
+
+ const auto __izone = [&] {
+ const _TimeZonePtr __tz = __val.get_time_zone();
+ if constexpr (is_same_v<_TimeZonePtr, const chrono::time_zone*>)
+ return reinterpret_cast<uintptr_t>(__tz);
+ else
+ return hash<_TimeZonePtr>{}(__tz);
+ }();
+
+ return chrono::__int_hash(__iduration, __izone);
+ }
+ };
+
+ template<typename _Duration, typename _TimeZonePtr>
+ struct __is_fast_hash<hash<chrono::zoned_time<_Duration, _TimeZonePtr>>>
+ : __and_<__is_fast_hash<hash<
+ typename chrono::zoned_time<_Duration, _TimeZonePtr>::duration>>,
+ __is_fast_hash<hash<_TimeZonePtr>>>
+ {};
+
+ // leap_second
+ template<>
+ struct hash<chrono::leap_second>
+ {
+ size_t
+ operator()(chrono::leap_second __val) const noexcept
+ {
+ return chrono::__int_hash(
+ __val.date().time_since_epoch().count(),
+ __val.value().count());
+ }
+ };
+#endif // _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
+#endif // _GLIBCXX_HOSTED
+#endif // __glibcxx_chrono_cxx20 >= 202306
+
+#ifdef __glibcxx_chrono_cxx20
inline namespace literals
{
inline namespace chrono_literals
@@ -3374,7 +3675,7 @@ namespace __detail
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#if __cplusplus >= 202002L && _GLIBCXX_HOSTED
+#if defined __glibcxx_chrono_cxx20 && _GLIBCXX_HOSTED
# include <bits/chrono_io.h>
#endif
diff --git a/libstdc++-v3/include/std/complex b/libstdc++-v3/include/std/complex
index 59ef905..4765425 100644
--- a/libstdc++-v3/include/std/complex
+++ b/libstdc++-v3/include/std/complex
@@ -96,7 +96,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp>
_GLIBCXX20_CONSTEXPR complex<_Tp> conj(const complex<_Tp>&);
/// Return complex with magnitude @a rho and angle @a theta.
- template<typename _Tp> complex<_Tp> polar(const _Tp&, const _Tp& = 0);
+ template<typename _Tp> complex<_Tp> polar(const _Tp&, const _Tp& = _Tp(0));
// Transcendentals:
/// Return complex cosine of @a z.
@@ -969,7 +969,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
- // 26.2.7/4: arg(__z): Returns the phase angle of __z.
+ // C++11 26.4.7 [complex.value.ops]/4: arg(z): Returns the phase angle of z.
template<typename _Tp>
inline _Tp
__complex_arg(const complex<_Tp>& __z)
@@ -1038,7 +1038,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline complex<_Tp>
polar(const _Tp& __rho, const _Tp& __theta)
{
- __glibcxx_assert( __rho >= 0 );
+ __glibcxx_assert( __rho >= _Tp(0) );
return complex<_Tp>(__rho * cos(__theta), __rho * sin(__theta));
}
@@ -1238,13 +1238,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__x == _Tp())
{
- _Tp __t = sqrt(abs(__y) / 2);
+ _Tp __t = sqrt(abs(__y) / _Tp(2));
return complex<_Tp>(__t, __y < _Tp() ? -__t : __t);
}
else
{
- _Tp __t = sqrt(2 * (std::abs(__z) + abs(__x)));
- _Tp __u = __t / 2;
+ _Tp __t = sqrt(_Tp(2) * (std::abs(__z) + abs(__x)));
+ _Tp __u = __t / _Tp(2);
return __x > _Tp()
? complex<_Tp>(__u, __y / __t)
: complex<_Tp>(abs(__y) / __t, __y < _Tp() ? -__u : __u);
@@ -1334,7 +1334,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
complex<_Tp>
__complex_pow_unsigned(complex<_Tp> __x, unsigned __n)
{
- complex<_Tp> __y = __n % 2 ? __x : complex<_Tp>(1);
+ complex<_Tp> __y = __n % 2 ? __x : complex<_Tp>(_Tp(1));
while (__n >>= 1)
{
@@ -1357,7 +1357,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
pow(const complex<_Tp>& __z, int __n)
{
return __n < 0
- ? complex<_Tp>(1) / std::__complex_pow_unsigned(__z, -(unsigned)__n)
+ ? complex<_Tp>(_Tp(1)) / std::__complex_pow_unsigned(__z,
+ -(unsigned)__n)
: std::__complex_pow_unsigned(__z, __n);
}
@@ -2123,8 +2124,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp> std::complex<_Tp> acosh(const std::complex<_Tp>&);
template<typename _Tp> std::complex<_Tp> asinh(const std::complex<_Tp>&);
template<typename _Tp> std::complex<_Tp> atanh(const std::complex<_Tp>&);
- // DR 595.
- template<typename _Tp> _Tp fabs(const std::complex<_Tp>&);
template<typename _Tp>
inline std::complex<_Tp>
@@ -2309,7 +2308,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
acos(const std::complex<_Tp>& __z)
{ return __complex_acos(__z.__rep()); }
#else
- /// acos(__z) [8.1.2].
+ /// acos(__z) C++11 26.4.8 [complex.transcendentals]
// Effects: Behaves the same as C99 function cacos, defined
// in subclause 7.3.5.1.
template<typename _Tp>
@@ -2345,7 +2344,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
asin(const std::complex<_Tp>& __z)
{ return __complex_asin(__z.__rep()); }
#else
- /// asin(__z) [8.1.3].
+ /// asin(__z) C++11 26.4.8 [complex.transcendentals]
// Effects: Behaves the same as C99 function casin, defined
// in subclause 7.3.5.2.
template<typename _Tp>
@@ -2389,7 +2388,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
atan(const std::complex<_Tp>& __z)
{ return __complex_atan(__z.__rep()); }
#else
- /// atan(__z) [8.1.4].
+ /// atan(__z) C++11 26.4.8 [complex.transcendentals]
// Effects: Behaves the same as C99 function catan, defined
// in subclause 7.3.5.3.
template<typename _Tp>
@@ -2425,7 +2424,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
acosh(const std::complex<_Tp>& __z)
{ return __complex_acosh(__z.__rep()); }
#else
- /// acosh(__z) [8.1.5].
+ /// acosh(__z) C++11 26.4.8 [complex.transcendentals]
// Effects: Behaves the same as C99 function cacosh, defined
// in subclause 7.3.6.1.
template<typename _Tp>
@@ -2464,7 +2463,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
asinh(const std::complex<_Tp>& __z)
{ return __complex_asinh(__z.__rep()); }
#else
- /// asinh(__z) [8.1.6].
+ /// asinh(__z) C++11 26.4.8 [complex.transcendentals]
// Effects: Behaves the same as C99 function casin, defined
// in subclause 7.3.6.2.
template<typename _Tp>
@@ -2508,7 +2507,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
atanh(const std::complex<_Tp>& __z)
{ return __complex_atanh(__z.__rep()); }
#else
- /// atanh(__z) [8.1.7].
+ /// atanh(__z) C++11 26.4.8 [complex.transcendentals]
// Effects: Behaves the same as C99 function catanh, defined
// in subclause 7.3.6.3.
template<typename _Tp>
@@ -2518,22 +2517,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
template<typename _Tp>
+ _GLIBCXX11_DEPRECATED_SUGGEST("std::abs")
inline _Tp
- /// fabs(__z) [8.1.8].
+ /// fabs(__z) TR1 8.1.8 [tr.c99.cmplx.fabs]
// Effects: Behaves the same as C99 function cabs, defined
// in subclause 7.3.8.1.
fabs(const std::complex<_Tp>& __z)
{ return std::abs(__z); }
- /// Additional overloads [8.1.9].
+ // Additional overloads C++11 26.4.9 [cmplx.over]
+
template<typename _Tp>
inline typename __gnu_cxx::__promote<_Tp>::__type
arg(_Tp __x)
{
typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
#if (_GLIBCXX11_USE_C99_MATH && !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC)
- return std::signbit(__x) ? __type(3.1415926535897932384626433832795029L)
- : __type();
+ return __builtin_signbit(__type(__x))
+ ? __type(3.1415926535897932384626433832795029L) : __type();
#else
return std::arg(std::complex<__type>(__x));
#endif
diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts
index 5899f03..870b0a4 100644
--- a/libstdc++-v3/include/std/concepts
+++ b/libstdc++-v3/include/std/concepts
@@ -204,7 +204,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
private:
template<typename _Tp, typename _Up>
- static constexpr bool
+ static consteval bool
_S_noexcept()
{
if constexpr (__adl_swap<_Tp, _Up>)
@@ -296,6 +296,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ { !static_cast<_Tp&&>(__t) } -> __boolean_testable_impl; };
} // namespace __detail
+ // [concept.comparisoncommontype], helpers for comparison common types
+ namespace __detail
+ {
+ template<typename _Tp, typename _Up,
+ typename _Cref = common_reference_t<const _Tp&, const _Up&>>
+ concept __comparison_common_type_with_impl
+ = same_as<common_reference_t<const _Tp&, const _Up&>,
+ common_reference_t<const _Up&, const _Tp&>>
+ && requires {
+ requires convertible_to<const _Tp&, const _Cref&>
+ || convertible_to<_Tp, const _Cref&>;
+ requires convertible_to<const _Up&, const _Cref&>
+ || convertible_to<_Up, const _Cref&>;
+ };
+
+ template<typename _Tp, typename _Up>
+ concept __comparison_common_type_with
+ = __comparison_common_type_with_impl<remove_cvref_t<_Tp>,
+ remove_cvref_t<_Up>>;
+ } // namespace __detail
+
// [concept.equalitycomparable], concept equality_comparable
namespace __detail
@@ -316,7 +337,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Up>
concept equality_comparable_with
= equality_comparable<_Tp> && equality_comparable<_Up>
- && common_reference_with<__detail::__cref<_Tp>, __detail::__cref<_Up>>
+ && __detail::__comparison_common_type_with<_Tp, _Up>
&& equality_comparable<common_reference_t<__detail::__cref<_Tp>,
__detail::__cref<_Up>>>
&& __detail::__weakly_eq_cmp_with<_Tp, _Up>;
diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable
index 3525ff3..dcf0b92 100644
--- a/libstdc++-v3/include/std/condition_variable
+++ b/libstdc++-v3/include/std/condition_variable
@@ -193,15 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__wait_until_impl(unique_lock<mutex>& __lock,
const chrono::time_point<steady_clock, _Dur>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
_M_cond.wait_until(*__lock.mutex(), CLOCK_MONOTONIC, __ts);
return (steady_clock::now() < __atime
@@ -214,15 +206,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__wait_until_impl(unique_lock<mutex>& __lock,
const chrono::time_point<system_clock, _Dur>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
_M_cond.wait_until(*__lock.mutex(), __ts);
return (system_clock::now() < __atime
diff --git a/libstdc++-v3/include/std/debugging b/libstdc++-v3/include/std/debugging
new file mode 100644
index 0000000..4cf7e4a
--- /dev/null
+++ b/libstdc++-v3/include/std/debugging
@@ -0,0 +1,77 @@
+// Debugging support -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/debugging
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_DEBUGGING
+#define _GLIBCXX_DEBUGGING 1
+
+#define __glibcxx_want_debugging
+#include <bits/version.h>
+
+#if __cpp_lib_debugging // C++ >= 26
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+// N.B. _GLIBCXX_BEGIN_NAMESPACE_VERSION is not used here.
+
+/** Try to determine if the program is running under control of a debugger.
+ *
+ * On GNU/Linux systems this function will only return true if the program
+ * is being traced by another program which is known to be a debugger.
+ * This is determined by checking the command name of the tracing program
+ * against a list of known debuggers, such as "gdb".
+ *
+ * On other POSIX-based systems, this function will return true if the
+ * program is being traced by any other process, which means it can return
+ * true for non-debugger utilities that use the ptrace system call.
+ *
+ * @since C++26
+ */
+bool
+is_debugger_present() noexcept;
+
+/** Stop the program with a breakpoint or debug trap.
+ *
+ * The details of how a breakpoint is implemented are platform-specific.
+ * Some systems provide a special instruction, such as `int3` in x86.
+ * When no more appropriate mechanism is available, this will stop the
+ * program using `__builtin_trap()`. It might not be possible for the
+ * program to continue after such a breakpoint.
+ *
+ * @since C++26
+ */
+void
+breakpoint() noexcept;
+
+/** Stop the program if it is running under control of a debugger.
+ *
+ * @since C++26
+ */
+void
+breakpoint_if_debugging() noexcept;
+
+} // namespace std
+#endif
+#endif // _GLIBCXX_DEBUGGING
diff --git a/libstdc++-v3/include/std/deque b/libstdc++-v3/include/std/deque
index 2badab8..600f607 100644
--- a/libstdc++-v3/include/std/deque
+++ b/libstdc++-v3/include/std/deque
@@ -66,7 +66,6 @@
#include <bits/stl_construct.h>
#include <bits/stl_uninitialized.h>
#include <bits/stl_deque.h>
-#include <bits/refwrap.h>
#include <bits/range_access.h>
#include <bits/deque.tcc>
@@ -101,19 +100,16 @@ namespace std _GLIBCXX_VISIBILITY(default)
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Alloc, typename _Predicate>
- inline typename deque<_Tp, _Alloc>::size_type
- erase_if(deque<_Tp, _Alloc>& __cont, _Predicate __pred)
+ inline typename _GLIBCXX_STD_C::deque<_Tp, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::deque<_Tp, _Alloc>& __cont, _Predicate __pred)
{
- using namespace __gnu_cxx;
- _GLIBCXX_STD_C::deque<_Tp, _Alloc>& __ucont = __cont;
const auto __osz = __cont.size();
- const auto __end = __ucont.end();
- auto __removed = std::__remove_if(__ucont.begin(), __end,
- __ops::__pred_iter(std::ref(__pred)));
+ const auto __end = __cont.end();
+ auto __removed = std::__remove_if(__cont.begin(), __end,
+ std::move(__pred));
if (__removed != __end)
{
- __cont.erase(__niter_wrap(__cont.begin(), __removed),
- __cont.end());
+ __cont.erase(__removed, __end);
return __osz - __cont.size();
}
@@ -122,24 +118,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Alloc,
typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
- inline typename deque<_Tp, _Alloc>::size_type
- erase(deque<_Tp, _Alloc>& __cont, const _Up& __value)
- {
- using namespace __gnu_cxx;
- _GLIBCXX_STD_C::deque<_Tp, _Alloc>& __ucont = __cont;
- const auto __osz = __cont.size();
- const auto __end = __ucont.end();
- auto __removed = std::__remove_if(__ucont.begin(), __end,
- __ops::__iter_equals_val(__value));
- if (__removed != __end)
- {
- __cont.erase(__niter_wrap(__cont.begin(), __removed),
- __cont.end());
- return __osz - __cont.size();
- }
+ inline typename _GLIBCXX_STD_C::deque<_Tp, _Alloc>::size_type
+ erase(_GLIBCXX_STD_C::deque<_Tp, _Alloc>& __cont, const _Up& __value)
+ { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); }
- return 0;
- }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // __cpp_lib_erase_if
diff --git a/libstdc++-v3/include/std/expected b/libstdc++-v3/include/std/expected
index 5dc1dfb..a03a7d3 100644
--- a/libstdc++-v3/include/std/expected
+++ b/libstdc++-v3/include/std/expected
@@ -474,6 +474,7 @@ namespace __expected
template<typename _Up = remove_cv_t<_Tp>>
requires (!is_same_v<remove_cvref_t<_Up>, expected>)
&& (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
+ && (!is_same_v<remove_cvref_t<_Up>, unexpect_t>)
&& is_constructible_v<_Tp, _Up>
&& (!__expected::__is_unexpected<remove_cvref_t<_Up>>)
&& __expected::__not_constructing_bool_from_expected<_Tp, _Up>
@@ -821,32 +822,36 @@ namespace __expected
return std::move(_M_unex);
}
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4406. value_or return statement is inconsistent with Mandates
template<typename _Up = remove_cv_t<_Tp>>
- constexpr _Tp
+ constexpr remove_cv_t<_Tp>
value_or(_Up&& __v) const &
noexcept(__and_v<is_nothrow_copy_constructible<_Tp>,
is_nothrow_convertible<_Up, _Tp>>)
{
- static_assert( is_copy_constructible_v<_Tp> );
+ using _Xp = remove_cv_t<_Tp>;
+ static_assert( is_convertible_v<const _Tp&, _Xp> );
static_assert( is_convertible_v<_Up, _Tp> );
if (_M_has_value)
return _M_val;
- return static_cast<_Tp>(std::forward<_Up>(__v));
+ return std::forward<_Up>(__v);
}
template<typename _Up = remove_cv_t<_Tp>>
- constexpr _Tp
+ constexpr remove_cv_t<_Tp>
value_or(_Up&& __v) &&
noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
is_nothrow_convertible<_Up, _Tp>>)
{
- static_assert( is_move_constructible_v<_Tp> );
- static_assert( is_convertible_v<_Up, _Tp> );
+ using _Xp = remove_cv_t<_Tp>;
+ static_assert( is_convertible_v<_Tp, _Xp> );
+ static_assert( is_convertible_v<_Up, _Xp> );
if (_M_has_value)
return std::move(_M_val);
- return static_cast<_Tp>(std::forward<_Up>(__v));
+ return std::forward<_Up>(__v);
}
template<typename _Gr = _Er>
@@ -1158,35 +1163,47 @@ namespace __expected
{ __t == __u } -> convertible_to<bool>;
{ __e == __e2 } -> convertible_to<bool>;
}
+ [[nodiscard]]
friend constexpr bool
operator==(const expected& __x, const expected<_Up, _Er2>& __y)
noexcept(noexcept(bool(*__x == *__y))
&& noexcept(bool(__x.error() == __y.error())))
{
+ if (__x.has_value() != __y.has_value())
+ return false;
if (__x.has_value())
- return __y.has_value() && bool(*__x == *__y);
- else
- return !__y.has_value() && bool(__x.error() == __y.error());
+ return *__x == *__y;
+ return __x.error() == __y.error();
}
- template<typename _Up>
+ template<typename _Up, same_as<_Tp> _Vp>
requires (!__expected::__is_expected<_Up>)
&& requires (const _Tp& __t, const _Up& __u) {
{ __t == __u } -> convertible_to<bool>;
}
+ [[nodiscard]]
friend constexpr bool
- operator==(const expected& __x, const _Up& __v)
+ operator==(const expected<_Vp, _Er>& __x, const _Up& __v)
noexcept(noexcept(bool(*__x == __v)))
- { return __x.has_value() && bool(*__x == __v); }
+ {
+ if (__x.has_value())
+ return *__x == __v;
+ return false;
+ }
template<typename _Er2>
requires requires (const _Er& __e, const _Er2& __e2) {
{ __e == __e2 } -> convertible_to<bool>;
}
+ [[nodiscard]]
friend constexpr bool
operator==(const expected& __x, const unexpected<_Er2>& __e)
noexcept(noexcept(bool(__x.error() == __e.error())))
- { return !__x.has_value() && bool(__x.error() == __e.error()); }
+ {
+ if (!__x.has_value())
+ return __x.error() == __e.error();
+ return false;
+ }
friend constexpr void
swap(expected& __x, expected& __y)
@@ -1836,24 +1853,31 @@ namespace __expected
&& requires (const _Er& __e, const _Er2& __e2) {
{ __e == __e2 } -> convertible_to<bool>;
}
+ [[nodiscard]]
friend constexpr bool
operator==(const expected& __x, const expected<_Up, _Er2>& __y)
noexcept(noexcept(bool(__x.error() == __y.error())))
{
+ if (__x.has_value() != __y.has_value())
+ return false;
if (__x.has_value())
- return __y.has_value();
- else
- return !__y.has_value() && bool(__x.error() == __y.error());
+ return true;
+ return __x.error() == __y.error();
}
template<typename _Er2>
requires requires (const _Er& __e, const _Er2& __e2) {
{ __e == __e2 } -> convertible_to<bool>;
}
+ [[nodiscard]]
friend constexpr bool
operator==(const expected& __x, const unexpected<_Er2>& __e)
noexcept(noexcept(bool(__x.error() == __e.error())))
- { return !__x.has_value() && bool(__x.error() == __e.error()); }
+ {
+ if (!__x.has_value())
+ return __x.error() == __e.error();
+ return false;
+ }
friend constexpr void
swap(expected& __x, expected& __y)
diff --git a/libstdc++-v3/include/std/flat_map b/libstdc++-v3/include/std/flat_map
index 405caa8..e48c3ea 100644
--- a/libstdc++-v3/include/std/flat_map
+++ b/libstdc++-v3/include/std/flat_map
@@ -873,7 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
[[nodiscard]]
friend bool
operator==(const _Derived& __x, const _Derived& __y)
- { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); }
+ {
+ return __x._M_cont.keys == __y._M_cont.keys
+ && __x._M_cont.values == __y._M_cont.values;
+ }
template<typename _Up = value_type>
[[nodiscard]]
@@ -890,14 +893,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __x.swap(__y); }
template<typename _Predicate>
- friend size_type
- erase_if(_Derived& __c, _Predicate __pred)
+ size_type
+ _M_erase_if(_Predicate __pred)
{
- auto __guard = __c._M_make_clear_guard();
- auto __zv = views::zip(__c._M_cont.keys, __c._M_cont.values);
- auto __sr = ranges::remove_if(__zv, __pred);
+ auto __guard = _M_make_clear_guard();
+ auto __zv = views::zip(_M_cont.keys, _M_cont.values);
+ auto __sr = ranges::remove_if(__zv, __pred,
+ [](const auto& __e) {
+ return const_reference(__e);
+ });
auto __erased = __sr.size();
- __c.erase(__c.end() - __erased, __c.end());
+ erase(end() - __erased, end());
__guard._M_disable();
return __erased;
}
@@ -947,7 +953,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
public:
using iterator_category = input_iterator_tag;
using iterator_concept = random_access_iterator_tag;
- using value_type = pair<const key_type, mapped_type>;
+ using value_type = pair<key_type, mapped_type>;
using reference = pair<const key_type&,
ranges::__maybe_const_t<_Const, mapped_type>&>;
using difference_type = ptrdiff_t;
@@ -1142,14 +1148,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// element access
mapped_type&
operator[](const key_type& __x)
- { return operator[]<const key_type>(__x); }
+ { return try_emplace(__x).first->second; }
mapped_type&
operator[](key_type&& __x)
- { return operator[]<key_type>(std::move(__x)); }
+ { return try_emplace(std::move(__x)).first->second; }
template<typename _Key2>
- requires same_as<remove_cvref_t<_Key2>, _Key> || __transparent_comparator<_Compare>
+ requires __transparent_comparator<_Compare>
mapped_type&
operator[](_Key2&& __x)
{ return try_emplace(std::forward<_Key2>(__x)).first->second; }
@@ -1329,6 +1335,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using _Impl::lower_bound;
using _Impl::upper_bound;
using _Impl::equal_range;
+
+ using _Impl::_M_erase_if;
};
template<typename _KeyContainer, typename _MappedContainer,
@@ -1412,6 +1420,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
&& uses_allocator_v<_MappedContainer, _Alloc>>
{ };
+ template<typename _Key, typename _Tp, typename _Compare,
+ typename _KeyContainer, typename _MappedContainer, typename _Predicate>
+ typename flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>::size_type
+ erase_if(flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& __c,
+ _Predicate __pred)
+ { return __c._M_erase_if(std::move(__pred)); }
+
/* Class template flat_multimap - container adaptor
*
* @ingroup
@@ -1487,6 +1502,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using _Impl::lower_bound;
using _Impl::upper_bound;
using _Impl::equal_range;
+
+ using _Impl::_M_erase_if;
};
template<typename _KeyContainer, typename _MappedContainer,
@@ -1571,6 +1588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
&& uses_allocator_v<_MappedContainer, _Alloc>>
{ };
+ template<typename _Key, typename _Tp, typename _Compare,
+ typename _KeyContainer, typename _MappedContainer, typename _Predicate>
+ typename flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>::size_type
+ erase_if(flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& __c,
+ _Predicate __pred)
+ { return __c._M_erase_if(std::move(__pred)); }
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // __cpp_lib_flat_map
diff --git a/libstdc++-v3/include/std/flat_set b/libstdc++-v3/include/std/flat_set
index 3e15d1a..c48340d 100644
--- a/libstdc++-v3/include/std/flat_set
+++ b/libstdc++-v3/include/std/flat_set
@@ -745,15 +745,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __x.swap(__y); }
template<typename _Predicate>
- friend size_type
- erase_if(_Derived& __c, _Predicate __pred)
+ size_type
+ _M_erase_if(_Predicate __pred)
{
- auto __guard = __c._M_make_clear_guard();
- auto __first = __c._M_cont.begin();
- auto __last = __c._M_cont.end();
+ auto __guard = _M_make_clear_guard();
+ auto __first = _M_cont.begin();
+ auto __last = _M_cont.end();
__first = std::remove_if(__first, __last, __pred);
auto __n = __last - __first;
- __c.erase(__first, __last);
+ erase(__first, __last);
__guard._M_disable();
return __n;
}
@@ -860,6 +860,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using _Impl::lower_bound;
using _Impl::upper_bound;
using _Impl::equal_range;
+
+ using _Impl::_M_erase_if;
};
template<typename _KeyContainer,
@@ -930,6 +932,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: bool_constant<uses_allocator_v<_KeyContainer, _Alloc>>
{ };
+ template<typename _Key, typename _Compare, typename _KeyContainer,
+ typename _Predicate>
+ typename flat_set<_Key, _Compare, _KeyContainer>::size_type
+ erase_if(flat_set<_Key, _Compare, _KeyContainer>& __c, _Predicate __pred)
+ { return __c._M_erase_if(std::move(__pred)); }
+
/* Class template flat_multiset - container adaptor
*
* @ingroup
@@ -999,6 +1007,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using _Impl::lower_bound;
using _Impl::upper_bound;
using _Impl::equal_range;
+
+ using _Impl::_M_erase_if;
};
template<typename _KeyContainer,
@@ -1069,6 +1079,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: bool_constant<uses_allocator_v<_KeyContainer, _Alloc>>
{ };
+ template<typename _Key, typename _Compare, typename _KeyContainer,
+ typename _Predicate>
+ typename flat_multiset<_Key, _Compare, _KeyContainer>::size_type
+ erase_if(flat_multiset<_Key, _Compare, _KeyContainer>& __c, _Predicate __pred)
+ { return __c._M_erase_if(std::move(__pred)); }
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // __cpp_lib_flat_set
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index e557e10..f64f35a 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -56,7 +56,7 @@
#include <bits/ranges_base.h> // input_range, range_reference_t
#include <bits/ranges_util.h> // subrange
#include <bits/ranges_algobase.h> // ranges::copy
-#include <bits/stl_iterator.h> // back_insert_iterator
+#include <bits/stl_iterator.h> // counted_iterator
#include <bits/stl_pair.h> // __is_pair
#include <bits/unicode.h> // __is_scalar_value, _Utf_view, etc.
#include <bits/utility.h> // tuple_size_v
@@ -99,24 +99,27 @@ namespace __format
// Size for stack located buffer
template<typename _CharT>
- constexpr size_t __stackbuf_size = 32 * sizeof(void*) / sizeof(_CharT);
+ constexpr size_t __stackbuf_size = 32 * sizeof(void*) / sizeof(_CharT);
// Type-erased character sinks.
template<typename _CharT> class _Sink;
template<typename _CharT> class _Fixedbuf_sink;
- template<typename _Seq> class _Seq_sink;
-
- template<typename _CharT, typename _Alloc = allocator<_CharT>>
- using _Str_sink
- = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>;
-
- // template<typename _CharT, typename _Alloc = allocator<_CharT>>
- // using _Vec_sink = _Seq_sink<vector<_CharT, _Alloc>>;
+ template<typename _Out, typename _CharT> class _Padding_sink;
+ template<typename _Out, typename _CharT> class _Escaping_sink;
// Output iterator that writes to a type-erase character sink.
template<typename _CharT>
class _Sink_iter;
+ // Output iterator that ignores the characters
+ template<typename _CharT>
+ class _Drop_iter;
+
+ // An unspecified output iterator type used in the `formattable` concept.
+ template<typename _CharT>
+ struct _Iter_for
+ { using type = _Drop_iter<_CharT>; };
+
template<typename _CharT>
using __format_context = basic_format_context<_Sink_iter<_CharT>, _CharT>;
@@ -135,6 +138,7 @@ namespace __format
template<typename, typename...> friend struct std::basic_format_string;
};
+
} // namespace __format
/// @endcond
@@ -473,37 +477,33 @@ namespace __format
return {0, nullptr};
}
- enum _Pres_type {
+ enum class _Pres_type : unsigned char {
_Pres_none = 0, // Default type (not valid for integer presentation types).
+ _Pres_s = 1, // For strings, bool, ranges
// Presentation types for integral types (including bool and charT).
- _Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c,
- // Presentation types for floating-point types.
- _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, _Pres_g, _Pres_G,
- _Pres_p = 0, _Pres_P, // For pointers.
- _Pres_s = 0, // For strings, bool
- _Pres_seq = 0, _Pres_str, // For ranges
- _Pres_esc = 0xf, // For strings, charT and ranges
- };
-
- enum _Align {
- _Align_default,
- _Align_left,
- _Align_right,
- _Align_centre,
+ _Pres_c = 2, _Pres_x, _Pres_X, _Pres_d, _Pres_o, _Pres_b, _Pres_B,
+ // Presentation types for floating-point types
+ _Pres_g = 1, _Pres_G, _Pres_a, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F,
+ // For pointers, the value are same as hexadecimal presentations for integers
+ _Pres_p = _Pres_x, _Pres_P = _Pres_X,
+ _Pres_max = 0xf,
};
+ using enum _Pres_type;
- enum _Sign {
+ enum class _Sign : unsigned char {
_Sign_default,
_Sign_plus,
_Sign_minus, // XXX does this need to be distinct from _Sign_default?
_Sign_space,
};
+ using enum _Sign;
- enum _WidthPrec {
+ enum _WidthPrec : unsigned char {
_WP_none, // No width/prec specified.
_WP_value, // Fixed width/prec specified.
_WP_from_arg // Use a formatting argument for width/prec.
};
+ using enum _WidthPrec;
template<typename _Context>
size_t
@@ -515,9 +515,17 @@ namespace __format
constexpr bool __is_xdigit(char __c)
{ return std::__detail::__from_chars_alnum_to_val(__c) < 16; }
+ // Used to make _Spec a non-C++98 POD, so the tail-padding is used.
+ // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#pod
+ struct _SpecBase
+ { };
+
template<typename _CharT>
- struct _Spec
+ struct _Spec : _SpecBase
{
+ unsigned short _M_width;
+ unsigned short _M_prec;
+ char32_t _M_fill = ' ';
_Align _M_align : 2;
_Sign _M_sign : 2;
unsigned _M_alt : 1;
@@ -525,12 +533,11 @@ namespace __format
unsigned _M_zero_fill : 1;
_WidthPrec _M_width_kind : 2;
_WidthPrec _M_prec_kind : 2;
+ unsigned _M_debug : 1;
_Pres_type _M_type : 4;
- unsigned _M_reserved : 1;
- unsigned _M_reserved2 : 16;
- unsigned short _M_width;
- unsigned short _M_prec;
- char32_t _M_fill = ' ';
+ unsigned _M_reserved : 8;
+ // This class has 8 bits of tail padding, that can be used by
+ // derived classes.
using iterator = typename basic_string_view<_CharT>::iterator;
@@ -570,7 +577,7 @@ namespace __format
char32_t __c = *__beg++;
if (__is_scalar_value(__c))
if (auto __next = __beg.base(); __next != __last)
- if (_Align __align = _S_align(*__next))
+ if (_Align __align = _S_align(*__next); __align != _Align_default)
{
_M_fill = __c;
_M_align = __align;
@@ -579,14 +586,14 @@ namespace __format
}
}
else if (__last - __first >= 2)
- if (_Align __align = _S_align(__first[1]))
+ if (_Align __align = _S_align(__first[1]); __align != _Align_default)
{
_M_fill = *__first;
_M_align = __align;
return __first + 2;
}
- if (_Align __align = _S_align(__first[0]))
+ if (_Align __align = _S_align(__first[0]); __align != _Align_default)
{
_M_fill = ' ';
_M_align = __align;
@@ -611,7 +618,7 @@ namespace __format
constexpr iterator
_M_parse_sign(iterator __first, iterator) noexcept
{
- if (_Sign __sign = _S_sign(*__first))
+ if (_Sign __sign = _S_sign(*__first); __sign != _Sign_default)
{
_M_sign = __sign;
return __first + 1;
@@ -838,7 +845,7 @@ namespace __format
{
// Encode fill char as multiple code units of type _CharT.
const char32_t __arr[1]{ __fill_char };
- _Utf_view<_CharT, const char32_t(&)[1]> __v(__arr);
+ _Utf_view<_CharT, span<const char32_t, 1>> __v(__arr);
basic_string<_CharT> __padstr(__v.begin(), __v.end());
__padding = __padstr;
while (__l-- > 0)
@@ -879,18 +886,37 @@ namespace __format
const size_t __nfill = __width - __estimated_width;
- if (__spec._M_align)
+ if (__spec._M_align != _Align_default)
__align = __spec._M_align;
return __format::__write_padded(__fc.out(), __str, __align, __nfill,
__spec._M_fill);
}
- // Values are indices into _Escapes::all.
+ template<typename _CharT>
+ size_t
+ __truncate(basic_string_view<_CharT>& __s, size_t __prec)
+ {
+ if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
+ {
+ if (__prec != (size_t)-1)
+ return __unicode::__truncate(__s, __prec);
+ else
+ return __unicode::__field_width(__s);
+ }
+ else
+ {
+ __s = __s.substr(0, __prec);
+ return __s.size();
+ }
+ }
+
enum class _Term_char : unsigned char {
- _Tc_quote = 12,
- _Tc_apos = 15
+ _Term_none,
+ _Term_quote,
+ _Term_apos,
};
+ using enum _Term_char;
template<typename _CharT>
struct _Escapes
@@ -901,10 +927,6 @@ namespace __format
_Str_view _S_all()
{ return _GLIBCXX_WIDEN("\t\\t\n\\n\r\\r\\\\\\\"\\\"'\\'\\u\\x"); }
- static constexpr
- _CharT _S_term(_Term_char __term)
- { return _S_all()[static_cast<unsigned char>(__term)]; }
-
static consteval
_Str_view _S_tab()
{ return _S_all().substr(0, 3); }
@@ -936,6 +958,21 @@ namespace __format
static consteval
_Str_view _S_x()
{ return _S_all().substr(20, 2); }
+
+ static constexpr
+ _Str_view _S_term(_Term_char __term)
+ {
+ switch (__term)
+ {
+ case _Term_none:
+ return _Str_view();
+ case _Term_quote:
+ return _S_quote().substr(0, 1);
+ case _Term_apos:
+ return _S_apos().substr(0, 1);
+ }
+ __builtin_unreachable();
+ }
};
template<typename _CharT>
@@ -980,9 +1017,9 @@ namespace __format
case _Esc::_S_bslash()[0]:
return true;
case _Esc::_S_quote()[0]:
- return __term == _Term_char::_Tc_quote;
+ return __term == _Term_quote;
case _Esc::_S_apos()[0]:
- return __term == _Term_char::_Tc_apos;
+ return __term == _Term_apos;
default:
return (__c >= 0 && __c < 0x20) || __c == 0x7f;
};
@@ -1032,6 +1069,17 @@ namespace __format
template<typename _Out, typename _CharT>
_Out
+ __write_escape_seqs(_Out __out, basic_string_view<_CharT> __units)
+ {
+ using _UChar = make_unsigned_t<_CharT>;
+ for (_CharT __c : __units)
+ __out = __format::__write_escape_seq(
+ __out, static_cast<_UChar>(__c), _Escapes<_CharT>::_S_x());
+ return __out;
+ }
+
+ template<typename _Out, typename _CharT>
+ _Out
__write_escaped_char(_Out __out, _CharT __c)
{
using _UChar = make_unsigned_t<_CharT>;
@@ -1051,9 +1099,8 @@ namespace __format
case _Esc::_S_apos()[0]:
return __format::__write(__out, _Esc::_S_apos().substr(1, 2));
default:
- return __format::__write_escape_seq(__out,
- static_cast<_UChar>(__c),
- _Esc::_S_u());
+ return __format::__write_escape_seq(
+ __out, static_cast<_UChar>(__c), _Esc::_S_u());
}
}
@@ -1089,12 +1136,10 @@ namespace __format
template<typename _CharT, typename _Out>
_Out
- __write_escaped_unicode(_Out __out,
- basic_string_view<_CharT> __str,
- _Term_char __term)
+ __write_escaped_unicode_part(_Out __out, basic_string_view<_CharT>& __str,
+ bool& __prev_esc, _Term_char __term)
{
using _Str_view = basic_string_view<_CharT>;
- using _UChar = make_unsigned_t<_CharT>;
using _Esc = _Escapes<_CharT>;
static constexpr char32_t __replace = U'\uFFFD';
@@ -1108,10 +1153,10 @@ namespace __format
}();
__unicode::_Utf_view<char32_t, _Str_view> __v(std::move(__str));
+ __str = {};
+
auto __first = __v.begin();
auto const __last = __v.end();
-
- bool __prev_esc = true;
while (__first != __last)
{
bool __esc_ascii = false;
@@ -1150,15 +1195,32 @@ namespace __format
__out = __format::__write_escaped_char(__out, *__first.base());
else if (__esc_unicode)
__out = __format::__write_escape_seq(__out, *__first, _Esc::_S_u());
- else // __esc_replace
- for (_CharT __c : _Str_view(__first.base(), __first._M_units()))
- __out = __format::__write_escape_seq(__out,
- static_cast<_UChar>(__c),
- _Esc::_S_x());
+ // __esc_replace
+ else if (_Str_view __units(__first.base(), __first._M_units());
+ __units.end() != __last.base())
+ __out = __format::__write_escape_seqs(__out, __units);
+ else
+ {
+ __str = __units;
+ return __out;
+ }
+
__prev_esc = true;
++__first;
-
}
+
+ return __out;
+ }
+
+ template<typename _CharT, typename _Out>
+ _Out
+ __write_escaped_unicode(_Out __out, basic_string_view<_CharT> __str,
+ _Term_char __term)
+ {
+ bool __prev_escape = true;
+ __out = __format::__write_escaped_unicode_part(__out, __str,
+ __prev_escape, __term);
+ __out = __format::__write_escape_seqs(__out, __str);
return __out;
}
@@ -1166,8 +1228,7 @@ namespace __format
_Out
__write_escaped(_Out __out, basic_string_view<_CharT> __str, _Term_char __term)
{
- *__out = _Escapes<_CharT>::_S_term(__term);
- ++__out;
+ __out = __format::__write(__out, _Escapes<_CharT>::_S_term(__term));
if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
__out = __format::__write_escaped_unicode(__out, __str, __term);
@@ -1178,8 +1239,7 @@ namespace __format
// TODO Handle non-ascii extended encoding
__out = __format::__write_escaped_ascii(__out, __str, __term);
- *__out = _Escapes<_CharT>::_S_term(__term);
- return ++__out;
+ return __format::__write(__out, _Escapes<_CharT>::_S_term(__term));
}
// A lightweight optional<locale>.
@@ -1301,11 +1361,14 @@ namespace __format
return __first;
if (*__first == 's')
- ++__first;
+ {
+ __spec._M_type = _Pres_s;
+ ++__first;
+ }
#if __glibcxx_format_ranges // C++ >= 23 && HOSTED
else if (*__first == '?')
{
- __spec._M_type = _Pres_esc;
+ __spec._M_debug = true;
++__first;
}
#endif
@@ -1321,107 +1384,90 @@ namespace __format
format(basic_string_view<_CharT> __s,
basic_format_context<_Out, _CharT>& __fc) const
{
- constexpr auto __term = __format::_Term_char::_Tc_quote;
- const auto __write_direct = [&]
- {
- if (_M_spec._M_type == _Pres_esc)
- return __format::__write_escaped(__fc.out(), __s, __term);
- else
- return __format::__write(__fc.out(), __s);
- };
+ if (_M_spec._M_debug)
+ return _M_format_escaped(__s, __fc);
if (_M_spec._M_width_kind == _WP_none
&& _M_spec._M_prec_kind == _WP_none)
- return __write_direct();
+ return __format::__write(__fc.out(), __s);
- const size_t __prec =
- _M_spec._M_prec_kind != _WP_none
- ? _M_spec._M_get_precision(__fc)
- : basic_string_view<_CharT>::npos;
+ const size_t __maxwidth = _M_spec._M_get_precision(__fc);
+ const size_t __width = __format::__truncate(__s, __maxwidth);
+ return __format::__write_padded_as_spec(__s, __width, __fc, _M_spec);
+ }
- const size_t __estimated_width = _S_trunc(__s, __prec);
- // N.B. Escaping only increases width
- if (_M_spec._M_get_width(__fc) <= __estimated_width
- && _M_spec._M_prec_kind == _WP_none)
- return __write_direct();
+ template<typename _Out>
+ _Out
+ _M_format_escaped(basic_string_view<_CharT> __s,
+ basic_format_context<_Out, _CharT>& __fc) const
+ {
+ const size_t __padwidth = _M_spec._M_get_width(__fc);
+ if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none)
+ return __format::__write_escaped(__fc.out(), __s, _Term_quote);
- if (_M_spec._M_type != _Pres_esc)
- return __format::__write_padded_as_spec(__s, __estimated_width,
- __fc, _M_spec);
+ const size_t __maxwidth = _M_spec._M_get_precision(__fc);
+ const size_t __width = __truncate(__s, __maxwidth);
+ // N.B. Escaping only increases width
+ if (__padwidth <= __width && _M_spec._M_prec_kind == _WP_none)
+ return __format::__write_escaped(__fc.out(), __s, _Term_quote);
- __format::_Str_sink<_CharT> __sink;
- __format::__write_escaped(__sink.out(), __s, __term);
- basic_string_view<_CharT> __escaped(__sink.view().data(),
- __sink.view().size());
- const size_t __escaped_width = _S_trunc(__escaped, __prec);
// N.B. [tab:format.type.string] defines '?' as
// Copies the escaped string ([format.string.escaped]) to the output,
// so precision seem to appy to escaped string.
- return __format::__write_padded_as_spec(__escaped, __escaped_width,
- __fc, _M_spec);
+ _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth, __maxwidth);
+ __format::__write_escaped(__sink.out(), __s, _Term_quote);
+ return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill);
}
#if __glibcxx_format_ranges // C++ >= 23 && HOSTED
template<ranges::input_range _Rg, typename _Out>
requires same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, _CharT>
- typename basic_format_context<_Out, _CharT>::iterator
+ _Out
_M_format_range(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const
{
- using _String = basic_string<_CharT>;
+ using _Range = remove_reference_t<_Rg>;
using _String_view = basic_string_view<_CharT>;
- if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
+ if constexpr (!is_lvalue_reference_v<_Rg>)
+ return _M_format_range<_Range&>(__rg, __fc);
+ else if constexpr (!is_const_v<_Range>
+ && __simply_formattable_range<_Range, _CharT>)
+ return _M_format_range<const _Range&>(__rg, __fc);
+ else if constexpr (ranges::contiguous_range<_Rg>)
{
- const size_t __n(ranges::distance(__rg));
- if constexpr (ranges::contiguous_range<_Rg>)
- return format(_String_view(ranges::data(__rg), __n), __fc);
- else if (__n <= __format::__stackbuf_size<_CharT>)
- {
- _CharT __buf[__format::__stackbuf_size<_CharT>];
- ranges::copy(__rg, __buf);
- return format(_String_view(__buf, __n), __fc);
- }
- else if constexpr (ranges::sized_range<_Rg>)
- return format(_String(from_range, __rg), __fc);
- else if constexpr (ranges::random_access_range<_Rg>)
- {
- ranges::iterator_t<_Rg> __first = ranges::begin(__rg);
- ranges::subrange __sub(__first, __first + __n);
- return format(_String(from_range, __sub), __fc);
- }
- else
- {
- // N.B. preserve the computed size
- ranges::subrange __sub(__rg, __n);
- return format(_String(from_range, __sub), __fc);
- }
+ _String_view __str(ranges::data(__rg),
+ size_t(ranges::distance(__rg)));
+ return format(__str, __fc);
}
else
- return format(_String(from_range, __rg), __fc);
+ {
+ auto __handle_debug = [this, &__rg]<typename _NOut>(_NOut __nout)
+ {
+ if (!_M_spec._M_debug)
+ return ranges::copy(__rg, std::move(__nout)).out;
+
+ _Escaping_sink<_NOut, _CharT>
+ __sink(std::move(__nout), _Term_quote);
+ ranges::copy(__rg, __sink.out());
+ return __sink._M_finish();
+ };
+
+ const size_t __padwidth = _M_spec._M_get_width(__fc);
+ if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none)
+ return __handle_debug(__fc.out());
+
+ _Padding_sink<_Out, _CharT>
+ __sink(__fc.out(), __padwidth, _M_spec._M_get_precision(__fc));
+ __handle_debug(__sink.out());
+ return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill);
+ }
}
constexpr void
set_debug_format() noexcept
- { _M_spec._M_type = _Pres_esc; }
+ { _M_spec._M_debug = true; }
#endif
private:
- static size_t
- _S_trunc(basic_string_view<_CharT>& __s, size_t __prec)
- {
- if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
- {
- if (__prec != basic_string_view<_CharT>::npos)
- return __unicode::__truncate(__s, __prec);
- else
- return __unicode::__field_width(__s);
- }
- else
- {
- __s = __s.substr(0, __prec);
- return __s.size();
- }
- }
-
_Spec<_CharT> _M_spec{};
};
@@ -1434,6 +1480,16 @@ namespace __format
static constexpr _Pres_type _AsBool = _Pres_s;
static constexpr _Pres_type _AsChar = _Pres_c;
+ __formatter_int() = default;
+
+ constexpr
+ __formatter_int(_Spec<_CharT> __spec) noexcept
+ : _M_spec(__spec)
+ {
+ if (_M_spec._M_type == _Pres_none)
+ _M_spec._M_type = _Pres_d;
+ }
+
constexpr typename basic_format_parse_context<_CharT>::iterator
_M_do_parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type)
{
@@ -1521,7 +1577,7 @@ namespace __format
case 's':
if (__type == _AsBool)
{
- __spec._M_type = _Pres_s; // same value (and meaning) as "none"
+ __spec._M_type = _Pres_s; // same meaning as "none" for bool
++__first;
}
break;
@@ -1529,7 +1585,7 @@ namespace __format
case '?':
if (__type == _AsChar)
{
- __spec._M_type = _Pres_esc;
+ __spec._M_debug = true;
++__first;
}
#endif
@@ -1550,7 +1606,8 @@ namespace __format
{
auto __end = _M_do_parse(__pc, _AsBool);
if (_M_spec._M_type == _Pres_s)
- if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill)
+ if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt
+ || _M_spec._M_zero_fill)
__throw_format_error("format error: format-spec contains "
"invalid formatting options for "
"'bool'");
@@ -1559,8 +1616,9 @@ namespace __format
else if constexpr (__char<_Tp>)
{
auto __end = _M_do_parse(__pc, _AsChar);
- if (_M_spec._M_type == _Pres_c || _M_spec._M_type == _Pres_esc)
- if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill
+ if (_M_spec._M_type == _Pres_c)
+ if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt
+ || _M_spec._M_zero_fill
/* XXX should be invalid? || _M_spec._M_localized */)
__throw_format_error("format error: format-spec contains "
"invalid formatting options for "
@@ -1672,51 +1730,34 @@ namespace __format
_M_spec);
}
- [[__gnu__::__always_inline__]]
- static size_t
- _S_character_width(_CharT __c)
- {
- // N.B. single byte cannot encode charcter of width greater than 1
- if constexpr (sizeof(_CharT) > 1u &&
- __unicode::__literal_encoding_is_unicode<_CharT>())
- return __unicode::__field_width(__c);
- else
- return 1u;
- }
-
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
_M_format_character(_CharT __c,
- basic_format_context<_Out, _CharT>& __fc) const
+ basic_format_context<_Out, _CharT>& __fc) const
{
- return __format::__write_padded_as_spec({&__c, 1u},
- _S_character_width(__c),
- __fc, _M_spec);
- }
+ basic_string_view<_CharT> __in(&__c, 1u);
+ size_t __width = 1u;
+ // N.B. single byte cannot encode character of width greater than 1
+ if constexpr (sizeof(_CharT) > 1u &&
+ __unicode::__literal_encoding_is_unicode<_CharT>())
+ __width = __unicode::__field_width(__c);
+
+ if (!_M_spec._M_debug)
+ return __format::__write_padded_as_spec(__in, __width,
+ __fc, _M_spec);
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- _M_format_character_escaped(_CharT __c,
- basic_format_context<_Out, _CharT>& __fc) const
- {
- using _Esc = _Escapes<_CharT>;
- constexpr auto __term = __format::_Term_char::_Tc_apos;
- const basic_string_view<_CharT> __in(&__c, 1u);
- if (_M_spec._M_get_width(__fc) <= 3u)
- return __format::__write_escaped(__fc.out(), __in, __term);
+ __width += 2;
+ if (_M_spec._M_get_width(__fc) <= __width)
+ return __format::__write_escaped(__fc.out(), __in, _Term_apos);
_CharT __buf[12];
- __format::_Fixedbuf_sink<_CharT> __sink(__buf);
- __format::__write_escaped(__sink.out(), __in, __term);
+ _Fixedbuf_sink<_CharT> __sink(__buf);
+ __format::__write_escaped(__sink.out(), __in, _Term_apos);
- const basic_string_view<_CharT> __escaped = __sink.view();
- size_t __estimated_width;
- if (__escaped[1] == _Esc::_S_bslash()[0]) // escape sequence
- __estimated_width = __escaped.size();
- else
- __estimated_width = 2 + _S_character_width(__c);
- return __format::__write_padded_as_spec(__escaped,
- __estimated_width,
+ __in = __sink.view();
+ if (__in[1] == _Escapes<_CharT>::_S_bslash()[0]) // escape sequence
+ __width = __in.size();
+ return __format::__write_padded_as_spec(__in, __width,
__fc, _M_spec);
}
@@ -1816,37 +1857,27 @@ namespace __format
__align, __nfill, __fill_char);
}
-#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
- template<typename _Tp>
- using make_unsigned_t
- = typename __conditional_t<(sizeof(_Tp) <= sizeof(long long)),
- std::make_unsigned<_Tp>,
- type_identity<unsigned __int128>>::type;
-
- // std::to_chars is not overloaded for int128 in strict mode.
- template<typename _Int>
- static to_chars_result
- to_chars(char* __first, char* __last, _Int __value, int __base)
- { return std::__to_chars_i<_Int>(__first, __last, __value, __base); }
-#endif
-
_Spec<_CharT> _M_spec{};
};
+#ifdef __BFLT16_DIG__
+ using __bflt16_t = decltype(0.0bf16);
+#endif
+
// Decide how 128-bit floating-point types should be formatted (or not).
- // When supported, the typedef __format::__float128_t is the type that
- // format arguments should be converted to for storage in basic_format_arg.
+ // When supported, the typedef __format::__flt128_t is the type that format
+ // arguments should be converted to before passing them to __formatter_fp.
// Define the macro _GLIBCXX_FORMAT_F128 to say they're supported.
- // _GLIBCXX_FORMAT_F128=1 means __float128, _Float128 etc. will be formatted
- // by converting them to long double (or __ieee128 for powerpc64le).
- // _GLIBCXX_FORMAT_F128=2 means basic_format_arg needs to enable explicit
- // support for _Float128, rather than formatting it as another type.
+ // The __float128, _Float128 will be formatted by converting them to:
+ // __ieee128 (same as __float128) when _GLIBCXX_FORMAT_F128=1,
+ // long double when _GLIBCXX_FORMAT_F128=2,
+ // _Float128 when _GLIBCXX_FORMAT_F128=3.
#undef _GLIBCXX_FORMAT_F128
#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
// Format 128-bit floating-point types using __ieee128.
- using __float128_t = __ieee128;
+ using __flt128_t = __ieee128;
# define _GLIBCXX_FORMAT_F128 1
#ifdef __LONG_DOUBLE_IEEE128__
@@ -1880,14 +1911,14 @@ namespace __format
#elif defined _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128
// Format 128-bit floating-point types using long double.
- using __float128_t = long double;
-# define _GLIBCXX_FORMAT_F128 1
+ using __flt128_t = long double;
+# define _GLIBCXX_FORMAT_F128 2
#elif __FLT128_DIG__ && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
// Format 128-bit floating-point types using _Float128.
- using __float128_t = _Float128;
-# define _GLIBCXX_FORMAT_F128 2
+ using __flt128_t = _Float128;
+# define _GLIBCXX_FORMAT_F128 3
# if __cplusplus == 202002L
// These overloads exist in the library, but are not declared for C++20.
@@ -2356,9 +2387,16 @@ namespace __format
const size_t __r = __str.size() - __e; // Length of remainder.
auto __overwrite = [&](_CharT* __p, size_t) {
// Apply grouping to the digits before the radix or exponent.
- auto __end = std::__add_grouping(__p, __np.thousands_sep(),
+ int __off = 0;
+ if (auto __c = __str.front(); __c == '-' || __c == '+' || __c == ' ')
+ {
+ *__p = __c;
+ __off = 1;
+ }
+ auto __end = std::__add_grouping(__p + __off, __np.thousands_sep(),
__grp.data(), __grp.size(),
- __str.data(), __str.data() + __e);
+ __str.data() + __off,
+ __str.data() + __e);
if (__r) // If there's a fractional part or exponent
{
if (__d != __str.npos)
@@ -2381,6 +2419,150 @@ namespace __format
_Spec<_CharT> _M_spec{};
};
+ template<__format::__char _CharT>
+ struct __formatter_ptr
+ {
+ __formatter_ptr() = default;
+
+ constexpr
+ __formatter_ptr(_Spec<_CharT> __spec) noexcept
+ : _M_spec(__spec)
+ { _M_set_default(_Pres_p); }
+
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type = _Pres_p)
+ {
+ __format::_Spec<_CharT> __spec{};
+ const auto __last = __pc.end();
+ auto __first = __pc.begin();
+
+ auto __finalize = [this, &__spec, __type] {
+ _M_spec = __spec;
+ _M_set_default(__type);
+ };
+
+ auto __finished = [&] {
+ if (__first == __last || *__first == '}')
+ {
+ __finalize();
+ return true;
+ }
+ return false;
+ };
+
+ if (__finished())
+ return __first;
+
+ __first = __spec._M_parse_fill_and_align(__first, __last);
+ if (__finished())
+ return __first;
+
+// _GLIBCXX_RESOLVE_LIB_DEFECTS
+// P2510R3 Formatting pointers
+#if __glibcxx_format >= 202304L
+ __first = __spec._M_parse_zero_fill(__first, __last);
+ if (__finished())
+ return __first;
+#endif
+
+ __first = __spec._M_parse_width(__first, __last, __pc);
+ if (__finished())
+ return __first;
+
+ if (*__first == 'p')
+ {
+ __spec._M_type = _Pres_p;
+ _M_spec._M_alt = !_M_spec._M_alt;
+ ++__first;
+ }
+#if __glibcxx_format >= 202304L
+ else if (*__first == 'P')
+ {
+ __spec._M_type = _Pres_P;
+ _M_spec._M_alt = !_M_spec._M_alt;
+ ++__first;
+ }
+#endif
+
+ if (__finished())
+ return __first;
+
+ __format::__failed_to_parse_format_spec();
+ }
+
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const
+ {
+ auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v);
+ char __buf[2 + sizeof(__v) * 2];
+ auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf),
+ __u, 16);
+ int __n = __ptr - __buf;
+ __buf[0] = '0';
+ __buf[1] = 'x';
+#if __glibcxx_format >= 202304L
+ if (_M_spec._M_type == __format::_Pres_P)
+ {
+ __buf[1] = 'X';
+ for (auto __p = __buf + 2; __p != __ptr; ++__p)
+#if __has_builtin(__builtin_toupper)
+ *__p = __builtin_toupper(*__p);
+#else
+ *__p = std::toupper(*__p);
+#endif
+ }
+#endif
+
+ basic_string_view<_CharT> __str;
+ if constexpr (is_same_v<_CharT, char>)
+ __str = string_view(__buf, __n);
+#ifdef _GLIBCXX_USE_WCHAR_T
+ else
+ {
+ auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
+ std::__to_wstring_numeric(__buf, __n, __p);
+ __str = wstring_view(__p, __n);
+ }
+#endif
+
+#if __glibcxx_format >= 202304L
+ if (_M_spec._M_zero_fill)
+ {
+ size_t __width = _M_spec._M_get_width(__fc);
+ if (__width <= __str.size())
+ return __format::__write(__fc.out(), __str);
+
+ auto __out = __fc.out();
+ // Write "0x" or "0X" prefix before zero-filling.
+ __out = __format::__write(std::move(__out), __str.substr(0, 2));
+ __str.remove_prefix(2);
+ size_t __nfill = __width - __n;
+ return __format::__write_padded(std::move(__out), __str,
+ __format::_Align_right,
+ __nfill, _CharT('0'));
+ }
+#endif
+
+ return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec,
+ __format::_Align_right);
+ }
+
+ private:
+ [[__gnu__::__always_inline__]]
+ constexpr void
+ _M_set_default(_Pres_type __type)
+ {
+ if (_M_spec._M_type == _Pres_none && __type != _Pres_none)
+ {
+ _M_spec._M_type = __type;
+ _M_spec._M_alt = !_M_spec._M_alt;
+ }
+ }
+
+ __format::_Spec<_CharT> _M_spec{};
+ };
+
} // namespace __format
/// @endcond
@@ -2400,11 +2582,8 @@ namespace __format
typename basic_format_context<_Out, _CharT>::iterator
format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const
{
- if (_M_f._M_spec._M_type == __format::_Pres_none
- || _M_f._M_spec._M_type == __format::_Pres_c)
+ if (_M_f._M_spec._M_type == __format::_Pres_c)
return _M_f._M_format_character(__u, __fc);
- else if (_M_f._M_spec._M_type == __format::_Pres_esc)
- return _M_f._M_format_character_escaped(__u, __fc);
else
return _M_f.format(static_cast<make_unsigned_t<_CharT>>(__u), __fc);
}
@@ -2412,13 +2591,18 @@ namespace __format
#if __glibcxx_format_ranges // C++ >= 23 && HOSTED
constexpr void
set_debug_format() noexcept
- { _M_f._M_spec._M_type = __format::_Pres_esc; }
+ { _M_f._M_spec._M_debug = true; }
#endif
private:
__format::__formatter_int<_CharT> _M_f;
};
+#if __glibcxx_print >= 202403L
+ template<__format::__char _CharT>
+ constexpr bool enable_nonlocking_formatter_optimization<_CharT> = true;
+#endif
+
#ifdef _GLIBCXX_USE_WCHAR_T
/// Format a char value for wide character output.
template<>
@@ -2436,11 +2620,8 @@ namespace __format
typename basic_format_context<_Out, wchar_t>::iterator
format(char __u, basic_format_context<_Out, wchar_t>& __fc) const
{
- if (_M_f._M_spec._M_type == __format::_Pres_none
- || _M_f._M_spec._M_type == __format::_Pres_c)
+ if (_M_f._M_spec._M_type == __format::_Pres_c)
return _M_f._M_format_character(__u, __fc);
- else if (_M_f._M_spec._M_type == __format::_Pres_esc)
- return _M_f._M_format_character_escaped(__u, __fc);
else
return _M_f.format(static_cast<unsigned char>(__u), __fc);
}
@@ -2448,7 +2629,7 @@ namespace __format
#if __glibcxx_format_ranges // C++ >= 23 && HOSTED
constexpr void
set_debug_format() noexcept
- { _M_f._M_spec._M_type = __format::_Pres_esc; }
+ { _M_f._M_spec._M_debug = true; }
#endif
private:
@@ -2483,6 +2664,11 @@ namespace __format
__format::__formatter_str<_CharT> _M_f;
};
+#if __glibcxx_print >= 202403L
+ template<__format::__char _CharT>
+ constexpr bool enable_nonlocking_formatter_optimization<_CharT*> = true;
+#endif
+
template<__format::__char _CharT>
struct formatter<const _CharT*, _CharT>
{
@@ -2508,6 +2694,12 @@ namespace __format
__format::__formatter_str<_CharT> _M_f;
};
+#if __glibcxx_print >= 202403L
+ template<__format::__char _CharT>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<const _CharT*> = true;
+#endif
+
template<__format::__char _CharT, size_t _Nm>
struct formatter<_CharT[_Nm], _CharT>
{
@@ -2532,6 +2724,11 @@ namespace __format
__format::__formatter_str<_CharT> _M_f;
};
+#if __glibcxx_print >= 202403L
+ template<__format::__char _CharT, size_t _Nm>
+ constexpr bool enable_nonlocking_formatter_optimization<_CharT[_Nm]> = true;
+#endif
+
template<typename _Traits, typename _Alloc>
struct formatter<basic_string<char, _Traits, _Alloc>, char>
{
@@ -2556,6 +2753,13 @@ namespace __format
__format::__formatter_str<char> _M_f;
};
+#if __glibcxx_print >= 202403L
+ template<typename _Tr, typename _Alloc>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<basic_string<char, _Tr, _Alloc>>
+ = true;
+#endif
+
#ifdef _GLIBCXX_USE_WCHAR_T
template<typename _Traits, typename _Alloc>
struct formatter<basic_string<wchar_t, _Traits, _Alloc>, wchar_t>
@@ -2580,6 +2784,14 @@ namespace __format
private:
__format::__formatter_str<wchar_t> _M_f;
};
+
+#if __glibcxx_print >= 202403L
+ template<typename _Tr, typename _Alloc>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<basic_string<wchar_t, _Tr, _Alloc>>
+ = true;
+#endif
+
#endif // USE_WCHAR_T
template<typename _Traits>
@@ -2606,6 +2818,13 @@ namespace __format
__format::__formatter_str<char> _M_f;
};
+#if __glibcxx_print >= 202403L
+ template<typename _Tr>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<basic_string_view<char, _Tr>>
+ = true;
+#endif
+
#ifdef _GLIBCXX_USE_WCHAR_T
template<typename _Traits>
struct formatter<basic_string_view<wchar_t, _Traits>, wchar_t>
@@ -2630,6 +2849,13 @@ namespace __format
private:
__format::__formatter_str<wchar_t> _M_f;
};
+
+#if __glibcxx_print >= 202403L
+ template<typename _Tr>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<basic_string_view<wchar_t, _Tr>>
+ = true;
+#endif
#endif // USE_WCHAR_T
/// @}
@@ -2654,12 +2880,14 @@ namespace __format
#endif
template<> inline constexpr bool __is_formattable_integer<char16_t> = false;
template<> inline constexpr bool __is_formattable_integer<char32_t> = false;
+
+ template<typename _Tp>
+ concept __formattable_integer = __is_formattable_integer<_Tp>;
}
/// @endcond
/// Format an integer.
- template<typename _Tp, __format::__char _CharT>
- requires __format::__is_formattable_integer<_Tp>
+ template<__format::__formattable_integer _Tp, __format::__char _CharT>
struct formatter<_Tp, _CharT>
{
formatter() = default;
@@ -2680,6 +2908,12 @@ namespace __format
__format::__formatter_int<_CharT> _M_f;
};
+#if __glibcxx_print >= 202403L
+ template<__format::__formattable_integer _Tp>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<_Tp> = true;
+#endif
+
#if defined __glibcxx_to_chars
/// Format a floating-point value.
template<__format::__formattable_float _Tp, __format::__char _CharT>
@@ -2701,6 +2935,12 @@ namespace __format
__format::__formatter_fp<_CharT> _M_f;
};
+#if __glibcxx_print >= 202403L
+ template<__format::__formattable_float _Tp>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<_Tp> = true;
+#endif
+
#if __LDBL_MANT_DIG__ == __DBL_MANT_DIG__
// Reuse __formatter_fp<C>::format<double, Out> for long double.
template<__format::__char _CharT>
@@ -2789,8 +3029,8 @@ namespace __format
};
#endif
-#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 == 1
- // Reuse __formatter_fp<C>::format<__float128_t, Out> for _Float128.
+#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128
+ // Use __formatter_fp<C>::format<__format::__flt128_t, Out> for _Float128.
template<__format::__char _CharT>
struct formatter<_Float128, _CharT>
{
@@ -2804,7 +3044,30 @@ namespace __format
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(_Float128 __u, basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f.format((__format::__float128_t)__u, __fc); }
+ { return _M_f.format((__format::__flt128_t)__u, __fc); }
+
+ private:
+ __format::__formatter_fp<_CharT> _M_f;
+ };
+#endif
+
+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 == 2
+ // Use __formatter_fp<C>::format<__format::__flt128_t, Out> for __float128,
+ // when long double is not 128bit IEEE type.
+ template<__format::__char _CharT>
+ struct formatter<__float128, _CharT>
+ {
+ formatter() = default;
+
+ [[__gnu__::__always_inline__]]
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ { return _M_f.parse(__pc); }
+
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__float128 __u, basic_format_context<_Out, _CharT>& __fc) const
+ { return _M_f.format((__format::__flt128_t)__u, __fc); }
private:
__format::__formatter_fp<_CharT> _M_f;
@@ -2814,7 +3077,7 @@ namespace __format
#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
// Reuse __formatter_fp<C>::format<float, Out> for bfloat16_t.
template<__format::__char _CharT>
- struct formatter<__gnu_cxx::__bfloat16_t, _CharT>
+ struct formatter<__format::__bflt16_t, _CharT>
{
formatter() = default;
@@ -2845,122 +3108,23 @@ namespace __format
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- {
- __format::_Spec<_CharT> __spec{};
- const auto __last = __pc.end();
- auto __first = __pc.begin();
-
- auto __finalize = [this, &__spec] {
- _M_spec = __spec;
- };
-
- auto __finished = [&] {
- if (__first == __last || *__first == '}')
- {
- __finalize();
- return true;
- }
- return false;
- };
-
- if (__finished())
- return __first;
-
- __first = __spec._M_parse_fill_and_align(__first, __last);
- if (__finished())
- return __first;
-
-// _GLIBCXX_RESOLVE_LIB_DEFECTS
-// P2510R3 Formatting pointers
-#if __glibcxx_format >= 202304L
- __first = __spec._M_parse_zero_fill(__first, __last);
- if (__finished())
- return __first;
-#endif
-
- __first = __spec._M_parse_width(__first, __last, __pc);
-
- if (__first != __last)
- {
- if (*__first == 'p')
- ++__first;
-#if __glibcxx_format >= 202304L
- else if (*__first == 'P')
- {
- __spec._M_type = __format::_Pres_P;
- ++__first;
- }
-#endif
- }
-
- if (__finished())
- return __first;
-
- __format::__failed_to_parse_format_spec();
- }
+ { return _M_f.parse(__pc); }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const
- {
- auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v);
- char __buf[2 + sizeof(__v) * 2];
- auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf),
- __u, 16);
- int __n = __ptr - __buf;
- __buf[0] = '0';
- __buf[1] = 'x';
-#if __glibcxx_format >= 202304L
- if (_M_spec._M_type == __format::_Pres_P)
- {
- __buf[1] = 'X';
- for (auto __p = __buf + 2; __p != __ptr; ++__p)
-#if __has_builtin(__builtin_toupper)
- *__p = __builtin_toupper(*__p);
-#else
- *__p = std::toupper(*__p);
-#endif
- }
-#endif
-
- basic_string_view<_CharT> __str;
- if constexpr (is_same_v<_CharT, char>)
- __str = string_view(__buf, __n);
-#ifdef _GLIBCXX_USE_WCHAR_T
- else
- {
- auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
- std::__to_wstring_numeric(__buf, __n, __p);
- __str = wstring_view(__p, __n);
- }
-#endif
-
-#if __glibcxx_format >= 202304L
- if (_M_spec._M_zero_fill)
- {
- size_t __width = _M_spec._M_get_width(__fc);
- if (__width <= __str.size())
- return __format::__write(__fc.out(), __str);
-
- auto __out = __fc.out();
- // Write "0x" or "0X" prefix before zero-filling.
- __out = __format::__write(std::move(__out), __str.substr(0, 2));
- __str.remove_prefix(2);
- size_t __nfill = __width - __n;
- return __format::__write_padded(std::move(__out), __str,
- __format::_Align_right,
- __nfill, _CharT('0'));
- }
-#endif
-
- return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec,
- __format::_Align_right);
- }
+ { return _M_f.format(__v, __fc); }
private:
- __format::_Spec<_CharT> _M_spec{};
+ __format::__formatter_ptr<_CharT> _M_f;
};
+#if __glibcxx_print >= 202403L
+ template<>
+ inline constexpr bool
+ enable_nonlocking_formatter_optimization<const void*> = true;
+#endif
+
template<__format::__char _CharT>
struct formatter<void*, _CharT>
{
@@ -2977,9 +3141,15 @@ namespace __format
{ return _M_f.format(__v, __fc); }
private:
- formatter<const void*, _CharT> _M_f;
+ __format::__formatter_ptr<_CharT> _M_f;
};
+#if __glibcxx_print >= 202403l
+ template<>
+ inline constexpr bool
+ enable_nonlocking_formatter_optimization<void*> = true;
+#endif
+
template<__format::__char _CharT>
struct formatter<nullptr_t, _CharT>
{
@@ -2996,87 +3166,44 @@ namespace __format
{ return _M_f.format(nullptr, __fc); }
private:
- formatter<const void*, _CharT> _M_f;
+ __format::__formatter_ptr<_CharT> _M_f;
};
/// @}
+#if __glibcxx_print >= 202403L
+ template<>
+ inline constexpr bool
+ enable_nonlocking_formatter_optimization<nullptr_t> = true;
+#endif
+
#if defined _GLIBCXX_USE_WCHAR_T && __glibcxx_format_ranges
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3944. Formatters converting sequences of char to sequences of wchar_t
- namespace __format { struct __disabled; }
+ struct __formatter_disabled
+ {
+ __formatter_disabled() = delete; // Cannot format char sequence to wchar_t
+ __formatter_disabled(const __formatter_disabled&) = delete;
+ __formatter_disabled& operator=(const __formatter_disabled&) = delete;
+ };
- // std::formatter<__disabled, C> uses the primary template, which is disabled.
template<>
struct formatter<char*, wchar_t>
- : private formatter<__format::__disabled, wchar_t> { };
+ : private __formatter_disabled { };
template<>
struct formatter<const char*, wchar_t>
- : private formatter<__format::__disabled, wchar_t> { };
+ : private __formatter_disabled { };
template<size_t _Nm>
struct formatter<char[_Nm], wchar_t>
- : private formatter<__format::__disabled, wchar_t> { };
+ : private __formatter_disabled { };
template<class _Traits, class _Allocator>
struct formatter<basic_string<char, _Traits, _Allocator>, wchar_t>
- : private formatter<__format::__disabled, wchar_t> { };
+ : private __formatter_disabled { };
template<class _Traits>
struct formatter<basic_string_view<char, _Traits>, wchar_t>
- : private formatter<__format::__disabled, wchar_t> { };
+ : private __formatter_disabled { };
#endif
-/// @cond undocumented
-namespace __format
-{
- template<typename _Tp, typename _Context,
- typename _Formatter
- = typename _Context::template formatter_type<remove_const_t<_Tp>>,
- typename _ParseContext
- = basic_format_parse_context<typename _Context::char_type>>
- concept __parsable_with
- = semiregular<_Formatter>
- && requires (_Formatter __f, _ParseContext __pc)
- {
- { __f.parse(__pc) } -> same_as<typename _ParseContext::iterator>;
- };
-
- template<typename _Tp, typename _Context,
- typename _Formatter
- = typename _Context::template formatter_type<remove_const_t<_Tp>>,
- typename _ParseContext
- = basic_format_parse_context<typename _Context::char_type>>
- concept __formattable_with
- = semiregular<_Formatter>
- && requires (const _Formatter __cf, _Tp&& __t, _Context __fc)
- {
- { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
- };
-
- // An unspecified output iterator type used in the `formattable` concept.
- template<typename _CharT>
- using _Iter_for = back_insert_iterator<basic_string<_CharT>>;
-
- template<typename _Tp, typename _CharT,
- typename _Context = basic_format_context<_Iter_for<_CharT>, _CharT>>
- concept __formattable_impl
- = __parsable_with<_Tp, _Context> && __formattable_with<_Tp, _Context>;
-
- template<typename _Formatter>
- concept __has_debug_format = requires(_Formatter __f)
- {
- __f.set_debug_format();
- };
-
-} // namespace __format
-/// @endcond
-
-#if __glibcxx_format_ranges // C++ >= 23 && HOSTED
- // [format.formattable], concept formattable
- template<typename _Tp, typename _CharT>
- concept formattable
- = __format::__formattable_impl<remove_reference_t<_Tp>, _CharT>;
-
-#endif // format_ranges
-
/// An iterator after the last character written, and the number of
/// characters that would have been written.
template<typename _Out>
@@ -3094,6 +3221,43 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
namespace __format
{
template<typename _CharT>
+ class _Drop_iter
+ {
+ public:
+ using iterator_category = output_iterator_tag;
+ using value_type = void;
+ using difference_type = ptrdiff_t;
+ using pointer = void;
+ using reference = void;
+
+ _Drop_iter() = default;
+ _Drop_iter(const _Drop_iter&) = default;
+ _Drop_iter& operator=(const _Drop_iter&) = default;
+
+ [[__gnu__::__always_inline__]]
+ constexpr _Drop_iter&
+ operator=(_CharT __c)
+ { return *this; }
+
+ [[__gnu__::__always_inline__]]
+ constexpr _Drop_iter&
+ operator=(basic_string_view<_CharT> __s)
+ { return *this; }
+
+ [[__gnu__::__always_inline__]]
+ constexpr _Drop_iter&
+ operator*() { return *this; }
+
+ [[__gnu__::__always_inline__]]
+ constexpr _Drop_iter&
+ operator++() { return *this; }
+
+ [[__gnu__::__always_inline__]]
+ constexpr _Drop_iter
+ operator++(int) { return *this; }
+ };
+
+ template<typename _CharT>
class _Sink_iter
{
_Sink<_CharT>* _M_sink = nullptr;
@@ -3144,6 +3308,10 @@ namespace __format
auto
_M_reserve(size_t __n) const
{ return _M_sink->_M_reserve(__n); }
+
+ bool
+ _M_discarding() const
+ { return _M_sink->_M_discarding(); }
};
// Abstract base class for type-erased character sinks.
@@ -3263,6 +3431,11 @@ namespace __format
_M_bump(size_t __n)
{ _M_next += __n; }
+ // Returns true if the _Sink is discarding incoming characters.
+ virtual bool
+ _M_discarding() const
+ { return false; }
+
public:
_Sink(const _Sink&) = delete;
_Sink& operator=(const _Sink&) = delete;
@@ -3318,12 +3491,12 @@ namespace __format
// A sink that fills a sequence (e.g. std::string, std::vector, std::deque).
// Writes to a buffer then appends that to the sequence when it fills up.
template<typename _Seq>
- class _Seq_sink final : public _Buf_sink<typename _Seq::value_type>
+ class _Seq_sink : public _Buf_sink<typename _Seq::value_type>
{
using _CharT = typename _Seq::value_type;
_Seq _M_seq;
-
+ protected:
// Transfer buffer contents to the sequence, so buffer can be refilled.
void
_M_overflow() override
@@ -3395,6 +3568,17 @@ namespace __format
}
}
+ void _M_trim(span<const _CharT> __s)
+ requires __is_specialization_of<_Seq, basic_string>
+ {
+ _GLIBCXX_DEBUG_ASSERT(__s.data() == this->_M_buf
+ || __s.data() == _M_seq.data());
+ if (__s.data() == _M_seq.data())
+ _M_seq.resize(__s.size());
+ else
+ this->_M_reset(this->_M_buf, __s.size());
+ }
+
public:
// TODO: for SSO string, use SSO buffer as initial span, then switch
// to _M_buf if it overflows? Or even do that for all unused capacity?
@@ -3420,7 +3604,7 @@ namespace __format
// A writable span that views everything written to the sink.
// Will be either a view over _M_seq or the used part of _M_buf.
span<_CharT>
- view()
+ _M_span()
{
auto __s = this->_M_used();
if (_M_seq.size())
@@ -3431,9 +3615,21 @@ namespace __format
}
return __s;
}
+
+ basic_string_view<_CharT>
+ view()
+ {
+ auto __span = _M_span();
+ return basic_string_view<_CharT>(__span.data(), __span.size());
+ }
};
- // A sink that writes to an output iterator.
+ template<typename _CharT, typename _Alloc = allocator<_CharT>>
+ using _Str_sink
+ = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>;
+
+ // template<typename _CharT, typename _Alloc = allocator<_CharT>>
+ // using _Vec_sink = _Seq_sink<vector<_CharTthis-> sink that writes to an output iterator.
// Writes to a fixed-size buffer and then flushes to the output iterator
// when the buffer fills up.
template<typename _CharT, typename _OutIter>
@@ -3465,6 +3661,14 @@ namespace __format
_M_count += __s.size();
}
+ bool
+ _M_discarding() const override
+ {
+ // format_to_n return total number of characters, that would be written,
+ // see C++20 [format.functions] p20
+ return false;
+ }
+
public:
[[__gnu__::__always_inline__]]
explicit
@@ -3527,6 +3731,14 @@ namespace __format
}
}
+ bool
+ _M_discarding() const override
+ {
+ // format_to_n return total number of characters, that would be written,
+ // see C++20 [format.functions] p20
+ return false;
+ }
+
typename _Sink<_CharT>::_Reservation
_M_reserve(size_t __n) final
{
@@ -3601,20 +3813,289 @@ namespace __format
}
};
- enum _Arg_t : unsigned char {
+ // A sink for handling the padded outputs (_M_padwidth) or truncated
+ // (_M_maxwidth). The handling is done by writting to buffer (_Str_strink)
+ // until sufficient number of characters is written. After that if sequence
+ // is longer than _M_padwidth it's written to _M_out, and further writes are
+ // either:
+ // * buffered and forwarded to _M_out, if below _M_maxwidth,
+ // * ignored otherwise
+ // If field width of written sequence is no greater than _M_padwidth, the
+ // sequence is written during _M_finish call.
+ template<typename _Out, typename _CharT>
+ class _Padding_sink : public _Str_sink<_CharT>
+ {
+ size_t _M_padwidth;
+ size_t _M_maxwidth;
+ _Out _M_out;
+ size_t _M_printwidth;
+
+ [[__gnu__::__always_inline__]]
+ bool
+ _M_ignoring() const
+ { return _M_printwidth >= _M_maxwidth; }
+
+ [[__gnu__::__always_inline__]]
+ bool
+ _M_buffering() const
+ {
+ if (_M_printwidth < _M_padwidth)
+ return true;
+ if (_M_maxwidth != (size_t)-1)
+ return _M_printwidth < _M_maxwidth;
+ return false;
+ }
+
+ void
+ _M_sync_discarding()
+ {
+ if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
+ if (_M_out._M_discarding())
+ _M_maxwidth = _M_printwidth;
+ }
+
+ void
+ _M_flush()
+ {
+ span<_CharT> __new = this->_M_used();
+ basic_string_view<_CharT> __str(__new.data(), __new.size());
+ _M_out = __format::__write(std::move(_M_out), __str);
+ _M_sync_discarding();
+ this->_M_rewind();
+ }
+
+ bool
+ _M_force_update()
+ {
+ auto __str = this->view();
+ // Compute actual field width, possibly truncated.
+ _M_printwidth = __format::__truncate(__str, _M_maxwidth);
+ if (_M_ignoring())
+ this->_M_trim(__str);
+ if (_M_buffering())
+ return true;
+
+ // We have more characters than padidng, no padding is needed,
+ // write direclty to _M_out.
+ if (_M_printwidth >= _M_padwidth)
+ {
+ _M_out = __format::__write(std::move(_M_out), __str);
+ _M_sync_discarding();
+ }
+ // We reached _M_maxwidth that is smaller than _M_padwidth.
+ // Store the prefix sequence in _M_seq, and free _M_buf.
+ else
+ _Str_sink<_CharT>::_M_overflow();
+
+ // Use internal buffer for writes to _M_out.
+ this->_M_reset(this->_M_buf);
+ return false;
+ }
+
+ bool
+ _M_update(size_t __new)
+ {
+ _M_printwidth += __new;
+ // Compute estimated width, to see if is not reduced.
+ if (_M_printwidth >= _M_padwidth || _M_printwidth >= _M_maxwidth)
+ return _M_force_update();
+ return true;
+ }
+
+ void
+ _M_overflow() override
+ {
+ // Ignore characters in buffer, and override it.
+ if (_M_ignoring())
+ this->_M_rewind();
+ // Write buffer to _M_out, and override it.
+ else if (!_M_buffering())
+ _M_flush();
+ // Update written count, and if input still should be buffered,
+ // flush the to _M_seq.
+ else if (_M_update(this->_M_used().size()))
+ _Str_sink<_CharT>::_M_overflow();
+ }
+
+ bool
+ _M_discarding() const override
+ { return _M_ignoring(); }
+
+ typename _Sink<_CharT>::_Reservation
+ _M_reserve(size_t __n) override
+ {
+ // Ignore characters in buffer, if any.
+ if (_M_ignoring())
+ this->_M_rewind();
+ else if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
+ if (!_M_buffering())
+ {
+ // Write pending characters if any
+ if (!this->_M_used().empty())
+ _M_flush();
+ // Try to reserve from _M_out sink.
+ if (auto __reserved = _M_out._M_reserve(__n))
+ return __reserved;
+ }
+ return _Sink<_CharT>::_M_reserve(__n);
+ }
+
+ void
+ _M_bump(size_t __n) override
+ {
+ // Ignore the written characters.
+ if (_M_ignoring())
+ return;
+ // If reservation was made directy sink associated _M_out,
+ // _M_bump will be called on that sink.
+ _Sink<_CharT>::_M_bump(__n);
+ if (_M_buffering())
+ _M_update(__n);
+ }
+
+ public:
+ [[__gnu__::__always_inline__]]
+ explicit
+ _Padding_sink(_Out __out, size_t __padwidth, size_t __maxwidth)
+ : _M_padwidth(__padwidth), _M_maxwidth(__maxwidth),
+ _M_out(std::move(__out)), _M_printwidth(0)
+ { _M_sync_discarding(); }
+
+ [[__gnu__::__always_inline__]]
+ explicit
+ _Padding_sink(_Out __out, size_t __padwidth)
+ : _Padding_sink(std::move(__out), __padwidth, (size_t)-1)
+ { }
+
+ _Out
+ _M_finish(_Align __align, char32_t __fill_char)
+ {
+ // Handle any characters in the buffer.
+ if (auto __rem = this->_M_used().size())
+ {
+ if (_M_ignoring())
+ this->_M_rewind();
+ else if (!_M_buffering())
+ _M_flush();
+ else
+ _M_update(__rem);
+ }
+
+ if (!_M_buffering() || !_M_force_update())
+ // Characters were already written to _M_out.
+ if (_M_printwidth >= _M_padwidth)
+ return std::move(_M_out);
+
+ const auto __str = this->view();
+ if (_M_printwidth >= _M_padwidth)
+ return __format::__write(std::move(_M_out), __str);
+
+ const size_t __nfill = _M_padwidth - _M_printwidth;
+ return __format::__write_padded(std::move(_M_out), __str,
+ __align, __nfill, __fill_char);
+ }
+ };
+
+ template<typename _Out, typename _CharT>
+ class _Escaping_sink : public _Buf_sink<_CharT>
+ {
+ using _Esc = _Escapes<_CharT>;
+
+ _Out _M_out;
+ _Term_char _M_term : 2;
+ unsigned _M_prev_escape : 1;
+ unsigned _M_out_discards : 1;
+
+ void
+ _M_sync_discarding()
+ {
+ if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
+ _M_out_discards = _M_out._M_discarding();
+ }
+
+ void
+ _M_write()
+ {
+ span<_CharT> __bytes = this->_M_used();
+ basic_string_view<_CharT> __str(__bytes.data(), __bytes.size());
+
+ size_t __rem = 0;
+ if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
+ {
+ bool __prev_escape = _M_prev_escape;
+ _M_out = __format::__write_escaped_unicode_part(
+ std::move(_M_out), __str, __prev_escape, _M_term);
+ _M_prev_escape = __prev_escape;
+
+ __rem = __str.size();
+ if (__rem > 0 && __str.data() != this->_M_buf) [[unlikely]]
+ ranges::move(__str, this->_M_buf);
+ }
+ else
+ _M_out = __format::__write_escaped_ascii(
+ std::move(_M_out), __str, _M_term);
+
+ this->_M_reset(this->_M_buf, __rem);
+ _M_sync_discarding();
+ }
+
+ void
+ _M_overflow() override
+ {
+ if (_M_out_discards)
+ this->_M_rewind();
+ else
+ _M_write();
+ }
+
+ bool
+ _M_discarding() const override
+ { return _M_out_discards; }
+
+ public:
+ [[__gnu__::__always_inline__]]
+ explicit
+ _Escaping_sink(_Out __out, _Term_char __term)
+ : _M_out(std::move(__out)), _M_term(__term),
+ _M_prev_escape(true), _M_out_discards(false)
+ {
+ _M_out = __format::__write(std::move(_M_out), _Esc::_S_term(_M_term));
+ _M_sync_discarding();
+ }
+
+ _Out
+ _M_finish()
+ {
+ if (_M_out_discards)
+ return std::move(_M_out);
+
+ if (!this->_M_used().empty())
+ {
+ _M_write();
+ if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
+ if (auto __rem = this->_M_used(); !__rem.empty())
+ {
+ basic_string_view<_CharT> __str(__rem.data(), __rem.size());
+ _M_out = __format::__write_escape_seqs(std::move(_M_out), __str);
+ }
+ }
+ return __format::__write(std::move(_M_out), _Esc::_S_term(_M_term));
+ }
+ };
+
+ enum class _Arg_t : unsigned char {
_Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull,
_Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle,
- _Arg_i128, _Arg_u128,
- _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, // These are unused.
+ _Arg_i128, _Arg_u128, _Arg_float128,
+ _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64,
+ _Arg_max_,
+
#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- _Arg_next_value_,
- _Arg_f128 = _Arg_ldbl,
- _Arg_ibm128 = _Arg_next_value_,
-#else
- _Arg_f128,
+ _Arg_ibm128 = _Arg_ldbl,
+ _Arg_ieee128 = _Arg_float128,
#endif
- _Arg_max_
};
+ using enum _Arg_t;
template<typename _Context>
struct _Arg_value
@@ -3640,6 +4121,12 @@ namespace __format
double _M_dbl;
#ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // No long double if it's ambiguous.
long double _M_ldbl;
+#else
+ __ibm128 _M_ibm128;
+ __ieee128 _M_ieee128;
+#endif
+#ifdef __SIZEOF_FLOAT128__
+ __float128 _M_float128;
#endif
const _CharT* _M_str;
basic_string_view<_CharT> _M_sv;
@@ -3649,11 +4136,17 @@ namespace __format
__int128 _M_i128;
unsigned __int128 _M_u128;
#endif
-#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- __ieee128 _M_f128;
- __ibm128 _M_ibm128;
-#elif _GLIBCXX_FORMAT_F128 == 2
- __float128_t _M_f128;
+#ifdef __BFLT16_DIG__
+ __bflt16_t _M_bf16;
+#endif
+#ifdef __FLT16_DIG__
+ _Float16 _M_f16;
+#endif
+#ifdef __FLT32_DIG__
+ _Float32 _M_f32;
+#endif
+#ifdef __FLT64_DIG__
+ _Float64 _M_f64;
#endif
};
@@ -3691,10 +4184,14 @@ namespace __format
else if constexpr (is_same_v<_Tp, long double>)
return __u._M_ldbl;
#else
- else if constexpr (is_same_v<_Tp, __ieee128>)
- return __u._M_f128;
else if constexpr (is_same_v<_Tp, __ibm128>)
return __u._M_ibm128;
+ else if constexpr (is_same_v<_Tp, __ieee128>)
+ return __u._M_ieee128;
+#endif
+#ifdef __SIZEOF_FLOAT128__
+ else if constexpr (is_same_v<_Tp, __float128>)
+ return __u._M_float128;
#endif
else if constexpr (is_same_v<_Tp, const _CharT*>)
return __u._M_str;
@@ -3708,9 +4205,21 @@ namespace __format
else if constexpr (is_same_v<_Tp, unsigned __int128>)
return __u._M_u128;
#endif
-#if _GLIBCXX_FORMAT_F128 == 2
- else if constexpr (is_same_v<_Tp, __float128_t>)
- return __u._M_f128;
+#ifdef __BFLT16_DIG__
+ else if constexpr (is_same_v<_Tp, __bflt16_t>)
+ return __u._M_bf16;
+#endif
+#ifdef __FLT16_DIG__
+ else if constexpr (is_same_v<_Tp, _Float16>)
+ return __u._M_f16;
+#endif
+#ifdef __FLT32_DIG__
+ else if constexpr (is_same_v<_Tp, _Float32>)
+ return __u._M_f32;
+#endif
+#ifdef __FLT64_DIG__
+ else if constexpr (is_same_v<_Tp, _Float64>)
+ return __u._M_f64;
#endif
else if constexpr (derived_from<_Tp, _HandleBase>)
return static_cast<_Tp&>(__u._M_handle);
@@ -3889,36 +4398,25 @@ namespace __format
else if constexpr (is_same_v<_Td, __ieee128>)
return type_identity<__ieee128>();
#endif
-
-#if defined(__FLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
- else if constexpr (is_same_v<_Td, _Float16>)
- return type_identity<float>();
+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128
+ else if constexpr (is_same_v<_Td, __float128>)
+ return type_identity<__float128>();
#endif
-
-#if defined(__BFLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
- else if constexpr (is_same_v<_Td, decltype(0.0bf16)>)
- return type_identity<float>();
+#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ else if constexpr (is_same_v<_Td, __format::__bflt16_t>)
+ return type_identity<__format::__bflt16_t>();
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ else if constexpr (is_same_v<_Td, _Float16>)
+ return type_identity<_Float16>();
#endif
-
#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
else if constexpr (is_same_v<_Td, _Float32>)
- return type_identity<float>();
+ return type_identity<_Float32>();
#endif
-
#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
else if constexpr (is_same_v<_Td, _Float64>)
- return type_identity<double>();
-#endif
-
-#if _GLIBCXX_FORMAT_F128
-# if __FLT128_DIG__
- else if constexpr (is_same_v<_Td, _Float128>)
- return type_identity<__format::__float128_t>();
-# endif
-# if __SIZEOF_FLOAT128__
- else if constexpr (is_same_v<_Td, __float128>)
- return type_identity<__format::__float128_t>();
-# endif
+ return type_identity<_Float64>();
#endif
else if constexpr (__is_specialization_of<_Td, basic_string_view>
|| __is_specialization_of<_Td, basic_string>)
@@ -3974,7 +4472,27 @@ namespace __format
else if constexpr (is_same_v<_Tp, __ibm128>)
return _Arg_ibm128;
else if constexpr (is_same_v<_Tp, __ieee128>)
- return _Arg_f128;
+ return _Arg_ieee128;
+#endif
+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128
+ else if constexpr (is_same_v<_Tp, __float128>)
+ return _Arg_float128;
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ else if constexpr (is_same_v<_Tp, __format::__bflt16_t>)
+ return _Arg_bf16;
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ else if constexpr (is_same_v<_Tp, _Float16>)
+ return _Arg_f16;
+#endif
+#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ else if constexpr (is_same_v<_Tp, _Float32>)
+ return _Arg_f32;
+#endif
+#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
+ else if constexpr (is_same_v<_Tp, _Float64>)
+ return _Arg_f64;
#endif
else if constexpr (is_same_v<_Tp, const _CharT*>)
return _Arg_str;
@@ -3988,11 +4506,6 @@ namespace __format
else if constexpr (is_same_v<_Tp, unsigned __int128>)
return _Arg_u128;
#endif
-
-#if _GLIBCXX_FORMAT_F128 == 2
- else if constexpr (is_same_v<_Tp, __format::__float128_t>)
- return _Arg_f128;
-#endif
else if constexpr (is_same_v<_Tp, handle>)
return _Arg_handle;
}
@@ -4065,13 +4578,33 @@ namespace __format
#ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
case _Arg_ldbl:
return std::forward<_Visitor>(__vis)(_M_val._M_ldbl);
+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128
+ case _Arg_float128:
+ return std::forward<_Visitor>(__vis)(_M_val._M_float128);
+#endif
#else
- case _Arg_f128:
- return std::forward<_Visitor>(__vis)(_M_val._M_f128);
case _Arg_ibm128:
return std::forward<_Visitor>(__vis)(_M_val._M_ibm128);
+ case _Arg_ieee128:
+ return std::forward<_Visitor>(__vis)(_M_val._M_ieee128);
#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ case _Arg_bf16:
+ return std::forward<_Visitor>(__vis)(_M_val._M_bf16);
#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ case _Arg_f16:
+ return std::forward<_Visitor>(__vis)(_M_val._M_f16);
+#endif
+#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ case _Arg_f32:
+ return std::forward<_Visitor>(__vis)(_M_val._M_f32);
+#endif
+#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
+ case _Arg_f64:
+ return std::forward<_Visitor>(__vis)(_M_val._M_f64);
+#endif
+#endif // __glibcxx_to_chars
case _Arg_str:
return std::forward<_Visitor>(__vis)(_M_val._M_str);
case _Arg_sv:
@@ -4089,14 +4622,7 @@ namespace __format
case _Arg_u128:
return std::forward<_Visitor>(__vis)(_M_val._M_u128);
#endif
-
-#if _GLIBCXX_FORMAT_F128 == 2
- case _Arg_f128:
- return std::forward<_Visitor>(__vis)(_M_val._M_f128);
-#endif
-
default:
- // _Arg_f16 etc.
__builtin_unreachable();
}
}
@@ -4182,7 +4708,7 @@ namespace __format
{
__UINT64_TYPE__ __packed_types = 0;
for (auto __i = __types.rbegin(); __i != __types.rend(); ++__i)
- __packed_types = (__packed_types << _Bits) | *__i;
+ __packed_types = (__packed_types << _Bits) | (unsigned)*__i;
return __packed_types;
}
} // namespace __format
@@ -4195,7 +4721,7 @@ namespace __format
static constexpr int _S_packed_type_mask = 0b11111;
static constexpr int _S_max_packed_args = 12;
- static_assert( __format::_Arg_max_ <= (1 << _S_packed_type_bits) );
+ static_assert( (unsigned)__format::_Arg_max_ <= (1u << _S_packed_type_bits) );
template<typename... _Args>
using _Store = __format::_Arg_store<_Context, _Args...>;
@@ -5147,24 +5673,7 @@ namespace __format
#endif
#if __glibcxx_format_ranges // C++ >= 23 && HOSTED
- // [format.range], formatting of ranges
- // [format.range.fmtkind], variable template format_kind
- enum class range_format {
- disabled,
- map,
- set,
- sequence,
- string,
- debug_string
- };
-
/// @cond undocumented
- template<typename _Rg>
- constexpr auto format_kind =
- __primary_template_not_defined(
- format_kind<_Rg> // you can specialize this for non-const input ranges
- );
-
template<typename _Tp>
consteval range_format
__fmt_kind()
@@ -5203,74 +5712,49 @@ namespace __format
const _Spec<_CharT>& __spec,
_Callback&& __call)
{
- // This is required to implement formatting with padding,
- // as we need to format to temporary buffer, using the same iterator.
- static_assert(is_same_v<_Out, __format::_Sink_iter<_CharT>>);
-
- if (__spec._M_get_width(__fc) == 0)
- return __call(__fc);
-
- struct _Restore_out
- {
- _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>& __fc)
- : _M_ctx(std::addressof(__fc)), _M_out(__fc.out())
- { }
-
- void _M_trigger()
- {
- if (_M_ctx)
- _M_ctx->advance_to(_M_out);
- _M_ctx = nullptr;
- }
-
- ~_Restore_out()
- { _M_trigger(); }
-
- private:
- basic_format_context<_Sink_iter<_CharT>, _CharT>* _M_ctx;
- _Sink_iter<_CharT> _M_out;
- };
-
- _Restore_out __restore(__fc);
- // TODO Consider double sinking, first buffer of width
- // size and then original sink, if first buffer is overun
- // we do not need to align
- _Str_sink<_CharT> __buf;
- __fc.advance_to(__buf.out());
- __call(__fc);
- __restore._M_trigger();
-
- basic_string_view<_CharT> __str(__buf.view());
- size_t __width;
- if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
- __width = __unicode::__field_width(__str);
+ if constexpr (is_same_v<_Out, _Drop_iter<_CharT>>)
+ return __fc.out();
else
- __width = __str.size();
+ {
+ // This is required to implement formatting with padding,
+ // as we need to format to temporary buffer, using the same iterator.
+ static_assert(is_same_v<_Out, _Sink_iter<_CharT>>);
+
+ const size_t __padwidth = __spec._M_get_width(__fc);
+ if (__padwidth == 0)
+ return __call(__fc);
+
+ struct _Restore_out
+ {
+ _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>& __fc)
+ : _M_ctx(std::addressof(__fc)), _M_out(__fc.out())
+ { }
+
+ void
+ _M_disarm()
+ { _M_ctx = nullptr; }
+
+ ~_Restore_out()
+ {
+ if (_M_ctx)
+ _M_ctx->advance_to(_M_out);
+ }
- return __format::__write_padded_as_spec(__str, __width, __fc, __spec);
+ private:
+ basic_format_context<_Sink_iter<_CharT>, _CharT>* _M_ctx;
+ _Sink_iter<_CharT> _M_out;
+ };
+
+ _Restore_out __restore(__fc);
+ _Padding_sink<_Sink_iter<_CharT>, _CharT> __sink(__fc.out(), __padwidth);
+ __fc.advance_to(__sink.out());
+ __call(__fc);
+ __fc.advance_to(__sink._M_finish(__spec._M_align, __spec._M_fill));
+ __restore._M_disarm();
+ return __fc.out();
+ }
}
- template<typename _Rg, typename _CharT>
- concept __const_formattable_range
- = ranges::input_range<const _Rg>
- && formattable<ranges::range_reference_t<const _Rg>, _CharT>;
-
- // _Rg& and const _Rg& are both formattable and use same formatter
- // specialization for their references.
- template<typename _Rg, typename _CharT>
- concept __simply_formattable_range
- = __const_formattable_range<_Rg, _CharT>
- && same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>,
- remove_cvref_t<ranges::range_reference_t<const _Rg>>>;
-
- template<typename _Rg, typename _CharT>
- using __maybe_const_range
- = __conditional_t<__const_formattable_range<_Rg, _CharT>, const _Rg, _Rg>;
-
- template<typename _Tp, typename _CharT>
- using __maybe_const
- = __conditional_t<formattable<const _Tp, _CharT>, const _Tp, _Tp>;
-
template<size_t _Pos, typename _Tp, typename _CharT>
struct __indexed_formatter_storage
{
@@ -5474,6 +5958,15 @@ namespace __format
{ return this->_M_format_elems(__p.first, __p.second, __fc); }
};
+#if __glibcxx_print >= 202406L
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4399. enable_nonlocking_formatter_optimization for pair and tuple needs remove_cvref_t
+ template<typename _Fp, typename _Sp>
+ constexpr bool enable_nonlocking_formatter_optimization<pair<_Fp, _Sp>>
+ = enable_nonlocking_formatter_optimization<remove_cvref_t<_Fp>>
+ && enable_nonlocking_formatter_optimization<remove_cvref_t<_Sp>>;
+#endif
+
template<__format::__char _CharT, formattable<_CharT>... _Tps>
struct formatter<tuple<_Tps...>, _CharT>
: __format::__tuple_formatter<_CharT, remove_cvref_t<_Tps>...>
@@ -5492,8 +5985,16 @@ namespace __format
{ return this->_M_format(__t, index_sequence_for<_Tps...>(), __fc); }
};
+#if __glibcxx_print >= 202406L
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4399. enable_nonlocking_formatter_optimization for pair and tuple needs remove_cvref_t
+ template<typename... _Tps>
+ constexpr bool enable_nonlocking_formatter_optimization<tuple<_Tps...>>
+ = (enable_nonlocking_formatter_optimization<remove_cvref_t<_Tps>> && ...);
+#endif
+
// [format.range.formatter], class template range_formatter
- template<typename _Tp, __format::__char _CharT = char>
+ template<typename _Tp, __format::__char _CharT>
requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT>
class range_formatter
{
@@ -5564,7 +6065,7 @@ namespace __format
if (*__first == '?')
{
++__first;
- __spec._M_type = __format::_Pres_esc;
+ __spec._M_debug = true;
if (__finished() || *__first != 's')
__throw_format_error("format error: '?' is allowed only in"
" combination with 's'");
@@ -5575,8 +6076,7 @@ namespace __format
++__first;
if constexpr (same_as<_Tp, _CharT>)
{
- if (__spec._M_type != __format::_Pres_esc)
- __spec._M_type = __format::_Pres_str;
+ __spec._M_type = __format::_Pres_s;
if (__finished())
return __finalize();
__throw_format_error("format error: element format specifier"
@@ -5658,8 +6158,7 @@ namespace __format
_M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc) const
{
if constexpr (same_as<_Tp, _CharT>)
- if (_M_spec._M_type == __format::_Pres_str
- || _M_spec._M_type == __format::_Pres_esc)
+ if (_M_spec._M_type == __format::_Pres_s)
{
__format::__formatter_str __fstr(_M_spec);
return __fstr._M_format_range(__rg, __fc);
@@ -5748,13 +6247,13 @@ namespace __format
constexpr void
set_separator(basic_string_view<_CharT> __sep) noexcept
- requires (!_S_range_format_is_string)
+ requires (format_kind<_Rg> == range_format::sequence)
{ _M_under.set_separator(__sep); }
constexpr void
set_brackets(basic_string_view<_CharT> __open,
basic_string_view<_CharT> __close) noexcept
- requires (!_S_range_format_is_string)
+ requires (format_kind<_Rg> == range_format::sequence)
{ _M_under.set_brackets(__open, __close); }
// We deviate from standard, that declares this as template accepting
@@ -5788,6 +6287,13 @@ namespace __format
range_formatter<_Vt, _CharT>>;
_Formatter_under _M_under;
};
+
+#if __glibcxx_print >= 202406L
+ template<ranges::input_range _Rg>
+ requires (format_kind<_Rg> != range_format::disabled)
+ constexpr bool enable_nonlocking_formatter_optimization<_Rg> = false;
+#endif
+
#endif // C++23 formatting ranges
#undef _GLIBCXX_WIDEN
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index 1077e96..570e9e9 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -52,8 +52,23 @@
#if __cplusplus >= 201103L
+#define __glibcxx_want_boyer_moore_searcher
+#define __glibcxx_want_bind_front
+#define __glibcxx_want_bind_back
+#define __glibcxx_want_constexpr_functional
+#define __glibcxx_want_copyable_function
+#define __glibcxx_want_function_ref
+#define __glibcxx_want_invoke
+#define __glibcxx_want_invoke_r
+#define __glibcxx_want_move_only_function
+#define __glibcxx_want_not_fn
+#define __glibcxx_want_ranges
+#define __glibcxx_want_reference_wrapper
+#define __glibcxx_want_common_reference_wrapper
+#define __glibcxx_want_transparent_operators
+#include <bits/version.h>
+
#include <tuple>
-#include <type_traits>
#include <bits/functional_hash.h>
#include <bits/invoke.h>
#include <bits/refwrap.h> // std::reference_wrapper and _Mem_fn_traits
@@ -69,26 +84,15 @@
# include <bits/stl_algobase.h> // std::search
#endif
#if __cplusplus >= 202002L
+# include <bits/binders.h>
# include <bits/ranges_cmp.h> // std::identity, ranges::equal_to etc.
# include <compare>
#endif
-#if __cplusplus > 202002L && _GLIBCXX_HOSTED
-# include <bits/move_only_function.h>
+#if __glibcxx_move_only_function || __glibcxx_copyable_function || \
+ __glibcxx_function_ref
+# include <bits/funcwrap.h>
#endif
-#define __glibcxx_want_boyer_moore_searcher
-#define __glibcxx_want_bind_front
-#define __glibcxx_want_bind_back
-#define __glibcxx_want_constexpr_functional
-#define __glibcxx_want_invoke
-#define __glibcxx_want_invoke_r
-#define __glibcxx_want_move_only_function
-#define __glibcxx_want_not_fn
-#define __glibcxx_want_ranges
-#define __glibcxx_want_reference_wrapper
-#define __glibcxx_want_transparent_operators
-#include <bits/version.h>
-
#endif // C++11
namespace std _GLIBCXX_VISIBILITY(default)
@@ -492,6 +496,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
# define _GLIBCXX_DEPR_BIND
#endif
+#if _GLIBCXX_EXPLICIT_THIS_PARAMETER
+ // Return a _Up that has the same cv-quals as _Tp.
+ template<typename _Tp, typename _Up> // _Up should be cv-unqualified
+ struct __cv_like
+ { using type = _Up; };
+
+ template<typename _Tp, typename _Up>
+ struct __cv_like<const _Tp, _Up>
+ { using type = const _Up; };
+
+ template<typename _Tp, typename _Up>
+ struct __cv_like<volatile _Tp, _Up>
+ { using type = volatile _Up; };
+
+ template<typename _Tp, typename _Up>
+ struct __cv_like<const volatile _Tp, _Up>
+ { using type = const volatile _Up; };
+
+ template<typename _Tp, typename _Up>
+ using __cv_like_t = typename __cv_like<_Tp, _Up>::type;
+#endif
+
/// Type of the function object returned from bind().
template<typename _Signature>
class _Bind;
@@ -561,6 +587,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using _Res_type_impl
= __invoke_result_t<_Fn&, _Mu_type<_BArgs, _CallArgs>&&...>;
+#if !_GLIBCXX_EXPLICIT_THIS_PARAMETER
template<typename _CallArgs>
using _Res_type = _Res_type_impl<_Functor, _CallArgs, _Bound_args...>;
@@ -573,6 +600,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typename __cv_quals<__dependent<_CallArgs>>::type,
_CallArgs,
typename __cv_quals<_Bound_args>::type...>;
+#endif
public:
template<typename... _Args>
@@ -590,6 +618,63 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Bind(const _Bind&) = default;
_Bind(_Bind&&) = default;
+#if _GLIBCXX_EXPLICIT_THIS_PARAMETER
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
+# pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this
+ template<typename... _Args,
+ typename _Self,
+ typename _Self_nonref = typename remove_reference<_Self>::type,
+ __enable_if_t<!is_volatile<_Self_nonref>::value, int> = 0,
+ typename _Result
+ = _Res_type_impl<__cv_like_t<_Self_nonref, _Functor>,
+ tuple<_Args...>,
+ __cv_like_t<_Self_nonref, _Bound_args>...>>
+ _GLIBCXX20_CONSTEXPR
+ _Result
+ operator()(this _Self&& __self, _Args&&... __args)
+ {
+ using _Bind_ref = __cv_like_t<_Self_nonref, _Bind>&;
+ if constexpr (is_const<_Self_nonref>::value)
+ return _Bind_ref(__self)
+ .template __call_c<_Result>(std::forward_as_tuple
+ (std::forward<_Args>(__args)...),
+ _Bound_indexes());
+ else
+ return _Bind_ref(__self)
+ .template __call<_Result>(std::forward_as_tuple
+ (std::forward<_Args>(__args)...),
+ _Bound_indexes());
+ }
+
+# if defined(_GLIBCXX_VOLATILE_BIND)
+ template<typename... _Args,
+ typename _Self,
+ typename _Self_nonref = typename remove_reference<_Self>::type,
+ __enable_if_t<is_volatile<_Self_nonref>::value, int> = 0,
+ typename _Result
+ = _Res_type_impl<__cv_like_t<_Self_nonref, _Functor>,
+ tuple<_Args...>,
+ __cv_like_t<_Self_nonref, _Bound_args>...>>
+ _GLIBCXX_DEPR_BIND
+ _Result
+ operator()(this _Self&& __self, _Args&&... __args)
+ {
+ using _Bind_ref = __cv_like_t<_Self_nonref, _Bind>&;
+ if constexpr (is_const<_Self_nonref>::value)
+ return _Bind_ref(__self)
+ .template __call_c_v<_Result>(std::forward_as_tuple
+ (std::forward<_Args>(__args)...),
+ _Bound_indexes());
+ else
+ return _Bind_ref(__self)
+ .template __call_v<_Result>(std::forward_as_tuple
+ (std::forward<_Args>(__args)...),
+ _Bound_indexes());
+ }
+# endif
+# pragma GCC diagnostic pop
+#else
// Call unqualified
template<typename... _Args,
typename _Result = _Res_type<tuple<_Args...>>>
@@ -639,6 +724,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Bound_indexes());
}
#endif // volatile
+#endif
};
/// Type of the function object returned from bind<R>().
@@ -919,116 +1005,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
std::forward<_BoundArgs>(__args)...);
}
-#ifdef __cpp_lib_bind_front // C++ >= 20
-
- template<typename _Fd, typename... _BoundArgs>
- struct _Bind_front
+#if __cpp_lib_bind_front >= 202306L || __cpp_lib_bind_back >= 202306L
+ template <auto __fn>
+ struct _Bind_fn_t
{
- static_assert(is_move_constructible_v<_Fd>);
- static_assert((is_move_constructible_v<_BoundArgs> && ...));
-
- // First parameter is to ensure this constructor is never used
- // instead of the copy/move constructor.
- template<typename _Fn, typename... _Args>
- explicit constexpr
- _Bind_front(int, _Fn&& __fn, _Args&&... __args)
- noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>,
- is_nothrow_constructible<_BoundArgs, _Args>...>::value)
- : _M_fd(std::forward<_Fn>(__fn)),
- _M_bound_args(std::forward<_Args>(__args)...)
- { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); }
-
-#if __cpp_explicit_this_parameter
- template<typename _Self, typename... _CallArgs>
- constexpr
- invoke_result_t<__like_t<_Self, _Fd>, __like_t<_Self, _BoundArgs>..., _CallArgs...>
- operator()(this _Self&& __self, _CallArgs&&... __call_args)
- noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>,
- __like_t<_Self, _BoundArgs>..., _CallArgs...>)
- {
- return _S_call(__like_t<_Self, _Bind_front>(__self), _BoundIndices(),
- std::forward<_CallArgs>(__call_args)...);
- }
-#else
- template<typename... _CallArgs>
- requires true
- constexpr
- invoke_result_t<_Fd&, _BoundArgs&..., _CallArgs...>
- operator()(_CallArgs&&... __call_args) &
- noexcept(is_nothrow_invocable_v<_Fd&, _BoundArgs&..., _CallArgs...>)
- {
- return _S_call(*this, _BoundIndices(),
- std::forward<_CallArgs>(__call_args)...);
- }
-
- template<typename... _CallArgs>
- requires true
- constexpr
- invoke_result_t<const _Fd&, const _BoundArgs&..., _CallArgs...>
- operator()(_CallArgs&&... __call_args) const &
- noexcept(is_nothrow_invocable_v<const _Fd&, const _BoundArgs&...,
- _CallArgs...>)
- {
- return _S_call(*this, _BoundIndices(),
- std::forward<_CallArgs>(__call_args)...);
- }
-
- template<typename... _CallArgs>
- requires true
- constexpr
- invoke_result_t<_Fd, _BoundArgs..., _CallArgs...>
- operator()(_CallArgs&&... __call_args) &&
- noexcept(is_nothrow_invocable_v<_Fd, _BoundArgs..., _CallArgs...>)
- {
- return _S_call(std::move(*this), _BoundIndices(),
- std::forward<_CallArgs>(__call_args)...);
- }
-
- template<typename... _CallArgs>
- requires true
- constexpr
- invoke_result_t<const _Fd, const _BoundArgs..., _CallArgs...>
- operator()(_CallArgs&&... __call_args) const &&
- noexcept(is_nothrow_invocable_v<const _Fd, const _BoundArgs...,
- _CallArgs...>)
- {
- return _S_call(std::move(*this), _BoundIndices(),
- std::forward<_CallArgs>(__call_args)...);
- }
-
- template<typename... _CallArgs>
- void operator()(_CallArgs&&...) & = delete;
-
- template<typename... _CallArgs>
- void operator()(_CallArgs&&...) const & = delete;
-
- template<typename... _CallArgs>
- void operator()(_CallArgs&&...) && = delete;
-
- template<typename... _CallArgs>
- void operator()(_CallArgs&&...) const && = delete;
-#endif
-
- private:
- using _BoundIndices = index_sequence_for<_BoundArgs...>;
-
- template<typename _Tp, size_t... _Ind, typename... _CallArgs>
- static constexpr
- decltype(auto)
- _S_call(_Tp&& __g, index_sequence<_Ind...>, _CallArgs&&... __call_args)
- {
- return std::invoke(std::forward<_Tp>(__g)._M_fd,
- std::get<_Ind>(std::forward<_Tp>(__g)._M_bound_args)...,
- std::forward<_CallArgs>(__call_args)...);
- }
-
- [[no_unique_address]] _Fd _M_fd;
- [[no_unique_address]] std::tuple<_BoundArgs...> _M_bound_args;
+ using _Fn = const decltype(__fn)&;
+ template <typename... _Args>
+ requires is_invocable_v<_Fn, _Args...>
+ constexpr static decltype(auto)
+ operator()(_Args&&... __args)
+ noexcept(is_nothrow_invocable_v<_Fn, _Args...>)
+ { return std::invoke(__fn, std::forward<_Args>(__args)...); }
};
+#endif
- template<typename _Fn, typename... _Args>
- using _Bind_front_t = _Bind_front<decay_t<_Fn>, decay_t<_Args>...>;
-
+#ifdef __cpp_lib_bind_front // C++ >= 20
/** Create call wrapper by partial application of arguments to function.
*
* The result of `std::bind_front(f, args...)` is a function object that
@@ -1047,57 +1038,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return _Bind_front_t<_Fn, _Args...>(0, std::forward<_Fn>(__fn),
std::forward<_Args>(__args)...);
}
-#endif // __cpp_lib_bind_front
-#ifdef __cpp_lib_bind_back // C++ >= 23
- template<typename _Fd, typename... _BoundArgs>
- struct _Bind_back
+#if __cpp_lib_bind_front >= 202306L
+ /** Create call wrapper by partial application of arguments to function.
+ *
+ * The result of `std::bind_front<fn>(bind_args...)` is a function object
+ * that stores the bound arguments, `bind_args...`. When that function
+ * object is invoked with `call_args...` it returns the result of calling
+ * `fn(bind_args..., call_args...)`.
+ *
+ * @since C++26
+ */
+ template<auto __fn, typename... _BindArgs>
+ constexpr decltype(auto)
+ bind_front(_BindArgs&&... __bind_args)
+ noexcept(__and_v<is_nothrow_constructible<_BindArgs>...>)
{
- static_assert(is_move_constructible_v<_Fd>);
- static_assert((is_move_constructible_v<_BoundArgs> && ...));
-
- // First parameter is to ensure this constructor is never used
- // instead of the copy/move constructor.
- template<typename _Fn, typename... _Args>
- explicit constexpr
- _Bind_back(int, _Fn&& __fn, _Args&&... __args)
- noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>,
- is_nothrow_constructible<_BoundArgs, _Args>...>::value)
- : _M_fd(std::forward<_Fn>(__fn)),
- _M_bound_args(std::forward<_Args>(__args)...)
- { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); }
-
- template<typename _Self, typename... _CallArgs>
- constexpr
- invoke_result_t<__like_t<_Self, _Fd>, _CallArgs..., __like_t<_Self, _BoundArgs>...>
- operator()(this _Self&& __self, _CallArgs&&... __call_args)
- noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>,
- _CallArgs..., __like_t<_Self, _BoundArgs>...>)
- {
- return _S_call(__like_t<_Self, _Bind_back>(__self), _BoundIndices(),
- std::forward<_CallArgs>(__call_args)...);
- }
-
- private:
- using _BoundIndices = index_sequence_for<_BoundArgs...>;
-
- template<typename _Tp, size_t... _Ind, typename... _CallArgs>
- static constexpr
- decltype(auto)
- _S_call(_Tp&& __g, index_sequence<_Ind...>, _CallArgs&&... __call_args)
- {
- return std::invoke(std::forward<_Tp>(__g)._M_fd,
- std::forward<_CallArgs>(__call_args)...,
- std::get<_Ind>(std::forward<_Tp>(__g)._M_bound_args)...);
- }
-
- [[no_unique_address]] _Fd _M_fd;
- [[no_unique_address]] std::tuple<_BoundArgs...> _M_bound_args;
- };
+ using _Fn = decltype(__fn);
+ if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+ static_assert(__fn != nullptr);
+
+ if constexpr (sizeof...(_BindArgs) == 0)
+ return _Bind_fn_t<__fn>{};
+ else
+ return _Bind_front_t<_Bind_fn_t<__fn>, _BindArgs...>(0,
+ _Bind_fn_t<__fn>{}, std::forward<_BindArgs>(__bind_args)...);
+ }
- template<typename _Fn, typename... _Args>
- using _Bind_back_t = _Bind_back<decay_t<_Fn>, decay_t<_Args>...>;
+#endif // __cpp_lib_bind_front // C++26
+#endif // __cpp_lib_bind_front
+#ifdef __cpp_lib_bind_back // C++ >= 23
/** Create call wrapper by partial application of arguments to function.
*
* The result of `std::bind_back(f, args...)` is a function object that
@@ -1116,6 +1087,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return _Bind_back_t<_Fn, _Args...>(0, std::forward<_Fn>(__fn),
std::forward<_Args>(__args)...);
}
+
+#if __cpp_lib_bind_back >= 202306L
+
+ /** Create call wrapper by partial application of arguments to function.
+ *
+ * The result of `std::bind_back<fn>(bind_args...)` is a function object
+ * that stores the arguments, `bind_args...`. When that function object
+ * is invoked with `call_args...` it returns the result of calling
+ * `fn(call_args..., bind_args...)`.
+ *
+ * @since C++26
+ */
+ template<auto __fn, typename... _BindArgs>
+ constexpr decltype(auto)
+ bind_back(_BindArgs&&... __bind_args)
+ noexcept(__and_v<is_nothrow_constructible<_BindArgs>...>)
+ {
+ using _Fn = decltype(__fn);
+ if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+ static_assert(__fn != nullptr);
+
+ if constexpr (sizeof...(_BindArgs) == 0)
+ return _Bind_fn_t<__fn>{};
+ else
+ return _Bind_back_t<_Bind_fn_t<__fn>, _BindArgs...>(0,
+ _Bind_fn_t<__fn>{}, std::forward<_BindArgs>(__bind_args)...);
+ }
+#endif // __cpp_lib_bind_back // C++26, nttp
#endif // __cpp_lib_bind_back
#if __cplusplus >= 201402L
@@ -1140,6 +1139,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Not_fn(_Not_fn&& __fn) = default;
~_Not_fn() = default;
+#if _GLIBCXX_EXPLICIT_THIS_PARAMETER
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this
+ template<typename _Self, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
+ decltype(_S_not<__inv_res_t<__like_t<_Self, _Fn>, _Args...>>())
+ operator()(this _Self&& __self, _Args&&... __args)
+ noexcept(__is_nothrow_invocable<__like_t<_Self, _Fn>, _Args...>::value
+ && noexcept(_S_not<__inv_res_t<__like_t<_Self, _Fn>, _Args...>>()))
+ {
+ return !std::__invoke(__like_t<_Self, _Not_fn>(__self)._M_fn,
+ std::forward<_Args>(__args)...);
+ }
+# pragma GCC diagnostic pop
+#else
// Macro to define operator() with given cv-qualifiers ref-qualifiers,
// forwarding _M_fn and the function arguments with the same qualifiers,
// and deducing the return type and exception-specification.
@@ -1165,6 +1179,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_NOT_FN_CALL_OP( && )
_GLIBCXX_NOT_FN_CALL_OP( const && )
#undef _GLIBCXX_NOT_FN_CALL_OP
+#endif
private:
_Fn _M_fn;
@@ -1216,7 +1231,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
return _Not_fn<std::decay_t<_Fn>>{std::forward<_Fn>(__fn), 0};
}
-#endif
+
+#if __cpp_lib_not_fn >= 202306L
+ /** Wrap a function type to create a function object that negates its result.
+ *
+ * The function template `std::not_fn` creates a "forwarding call wrapper",
+ * which is a function object that when called forwards its arguments to
+ * its invocable template argument.
+ *
+ * The result of invoking the wrapper is the negation (using `!`) of
+ * the wrapped function object.
+ *
+ * @ingroup functors
+ * @since C++26
+ */
+ template<auto __fn>
+ constexpr decltype(auto)
+ not_fn() noexcept
+ {
+ using _Fn = decltype(__fn);
+ if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+ static_assert(__fn != nullptr);
+ return []<typename... _Args>(_Args&&... __args) static
+ noexcept(noexcept(
+ !std::invoke(__fn, std::forward<_Args>(__args)...) ))
+ -> decltype(auto)
+ requires requires {
+ !std::invoke(__fn, std::forward<_Args>(__args)...); }
+ { return !std::invoke(__fn, std::forward<_Args>(__args)...); };
+ };
+#endif // __cpp_lib_not_fn >= 202306L
+#endif // __cpp_lib_not_fn
#if __cplusplus >= 201703L
// Searchers
@@ -1410,6 +1455,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator()(_RandomAccessIterator2 __first,
_RandomAccessIterator2 __last) const
{
+#ifdef __glibcxx_concepts // >= C++20
+ // Value types must be the same for hash function and predicate
+ // to give consistent results for lookup in the map.
+ static_assert(is_same_v<iter_value_t<_RAIter>,
+ iter_value_t<_RandomAccessIterator2>>);
+#endif
const auto& __pred = this->_M_pred();
auto __patlen = _M_pat_end - _M_pat;
if (__patlen == 0)
@@ -1471,6 +1522,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator()(_RandomAccessIterator2 __first,
_RandomAccessIterator2 __last) const
{
+#ifdef __glibcxx_concepts // >= C++20
+ // Value types must be the same for hash function and predicate
+ // to give consistent results for lookup in the map.
+ static_assert(is_same_v<iter_value_t<_RAIter>,
+ iter_value_t<_RandomAccessIterator2>>);
+#endif
auto __patlen = _M_pat_end - _M_pat;
if (__patlen == 0)
return std::make_pair(__first, __first);
@@ -1487,7 +1544,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
if (__j < 0)
{
- const auto __match = __first + __i + 1;
+ const auto __match = __first + __diff_type(__i + 1);
return std::make_pair(__match, __match + __patlen);
}
__i += std::max(_M_bad_char_shift(__first[__i]),
diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future
index b7ab233..0806900 100644
--- a/libstdc++-v3/include/std/future
+++ b/libstdc++-v3/include/std/future
@@ -1486,12 +1486,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)> final
: __future_base::_Task_state_base<_Res(_Args...)>
{
+#ifdef __cpp_lib_is_invocable // C++ >= 17
+ static_assert(is_invocable_r_v<_Res, _Fn&, _Args...>);
+#else
+ static_assert(__is_invocable<_Fn&, _Args...>::value,
+ "_Fn& is invocable with _Args...");
+#endif
+
template<typename _Fn2>
_Task_state(_Fn2&& __fn, const _Alloc& __a)
: _Task_state_base<_Res(_Args...)>(__a),
_M_impl(std::forward<_Fn2>(__fn), __a)
{ }
+ template<typename _Fn2>
+ static shared_ptr<_Task_state_base<_Res(_Args...)>>
+ _S_create(_Fn2&& __fn, const _Alloc& __a)
+ {
+ return std::allocate_shared<_Task_state>(__a,
+ std::forward<_Fn2>(__fn),
+ __a);
+ }
+
private:
virtual void
_M_run(_Args&&... __args)
@@ -1515,7 +1531,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
virtual shared_ptr<_Task_state_base<_Res(_Args...)>>
- _M_reset();
+ _M_reset()
+ { return _S_create(std::move(_M_impl._M_fn), _M_impl); }
struct _Impl : _Alloc
{
@@ -1525,38 +1542,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Fn _M_fn;
} _M_impl;
};
-
- template<typename _Signature, typename _Fn,
- typename _Alloc = std::allocator<int>>
- shared_ptr<__future_base::_Task_state_base<_Signature>>
- __create_task_state(_Fn&& __fn, const _Alloc& __a = _Alloc())
- {
- typedef typename decay<_Fn>::type _Fn2;
- typedef __future_base::_Task_state<_Fn2, _Alloc, _Signature> _State;
- return std::allocate_shared<_State>(__a, std::forward<_Fn>(__fn), __a);
- }
-
- template<typename _Fn, typename _Alloc, typename _Res, typename... _Args>
- shared_ptr<__future_base::_Task_state_base<_Res(_Args...)>>
- __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)>::_M_reset()
- {
- return __create_task_state<_Res(_Args...)>(std::move(_M_impl._M_fn),
- static_cast<_Alloc&>(_M_impl));
- }
/// @endcond
/// packaged_task
template<typename _Res, typename... _ArgTypes>
class packaged_task<_Res(_ArgTypes...)>
{
- typedef __future_base::_Task_state_base<_Res(_ArgTypes...)> _State_type;
+ using _State_type = __future_base::_Task_state_base<_Res(_ArgTypes...)>;
shared_ptr<_State_type> _M_state;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3039. Unnecessary decay in thread and packaged_task
template<typename _Fn, typename _Fn2 = __remove_cvref_t<_Fn>>
- using __not_same
- = typename enable_if<!is_same<packaged_task, _Fn2>::value>::type;
+ using __not_same = __enable_if_t<!is_same<packaged_task, _Fn2>::value>;
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4154. The Mandates for std::packaged_task's constructor
+ // from a callable entity should consider decaying.
+ template<typename _Fn, typename _Alloc = std::allocator<int>>
+ using _Task_state
+ = __future_base::_Task_state<__decay_t<_Fn>, _Alloc,
+ _Res(_ArgTypes...)>;
public:
// Construction and destruction
@@ -1565,16 +1571,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Fn, typename = __not_same<_Fn>>
explicit
packaged_task(_Fn&& __fn)
- : _M_state(
- __create_task_state<_Res(_ArgTypes...)>(std::forward<_Fn>(__fn)))
- {
-#ifdef __cpp_lib_is_invocable // C++ >= 17
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 4154. The Mandates for std::packaged_task's constructor
- // from a callable entity should consider decaying
- static_assert(is_invocable_r_v<_Res, decay_t<_Fn>&, _ArgTypes...>);
-#endif
- }
+ : _M_state(_Task_state<_Fn>::_S_create(std::forward<_Fn>(__fn), {}))
+ { }
#if __cplusplus < 201703L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -1583,8 +1581,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// 2921. packaged_task and type-erased allocators
template<typename _Fn, typename _Alloc, typename = __not_same<_Fn>>
packaged_task(allocator_arg_t, const _Alloc& __a, _Fn&& __fn)
- : _M_state(__create_task_state<_Res(_ArgTypes...)>(
- std::forward<_Fn>(__fn), __a))
+ : _M_state(_Task_state<_Fn, _Alloc>::_S_create(std::forward<_Fn>(__fn),
+ __a))
{ }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
diff --git a/libstdc++-v3/include/std/generator b/libstdc++-v3/include/std/generator
index 3f781f1..7ab2c9e 100644
--- a/libstdc++-v3/include/std/generator
+++ b/libstdc++-v3/include/std/generator
@@ -153,6 +153,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept
{ return _Recursive_awaiter { std::move(__r.range) }; }
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3899. co_yielding elements of an lvalue generator is
+ // unnecessarily inefficient
+ template<typename _R2, typename _V2, typename _A2, typename _U2>
+ requires std::same_as<_Yield2_t<_R2, _V2>, _Yielded>
+ auto
+ yield_value(ranges::elements_of<generator<_R2, _V2, _A2>&, _U2> __r)
+ noexcept
+ { return _Recursive_awaiter { std::move(__r.range) }; }
+
template<ranges::input_range _R, typename _Alloc>
requires convertible_to<ranges::range_reference_t<_R>, _Yielded>
auto
diff --git a/libstdc++-v3/include/std/inplace_vector b/libstdc++-v3/include/std/inplace_vector
new file mode 100644
index 0000000..0f7716c
--- /dev/null
+++ b/libstdc++-v3/include/std/inplace_vector
@@ -0,0 +1,1369 @@
+// Sequence container with fixed capacity -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/inplace_vector
+ * This is a Standard C++ Library header.
+ * @ingroup sequences
+ */
+
+#ifndef _GLIBCXX_INPLACE_VECTOR
+#define _GLIBCXX_INPLACE_VECTOR 1
+
+#pragma GCC system_header
+
+#define __glibcxx_want_inplace_vector
+#include <bits/version.h>
+
+#ifdef __glibcxx_inplace_vector // C++ >= 26
+#include <compare>
+#include <initializer_list>
+#include <bits/range_access.h>
+#include <bits/ranges_base.h> // borrowed_iterator_t, __detail::__container_compatible_range
+#include <bits/ranges_util.h> // subrange
+#include <bits/ranges_uninitialized.h>
+#include <bits/stl_construct.h>
+#include <bits/stl_uninitialized.h>
+#include <bits/stl_algo.h> // rotate
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+_GLIBCXX_BEGIN_NAMESPACE_CONTAINER
+
+ // [indirect], class template indirect
+ template<typename _Tp, size_t _Nm>
+ class inplace_vector
+ {
+ public:
+
+ // types:
+ using value_type = _Tp;
+ using pointer = _Tp*;
+ using const_pointer = const _Tp*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using iterator
+ = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>;
+ using const_iterator
+ = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // [containers.sequences.inplace.vector.cons], construct/copy/destroy
+ constexpr
+ inplace_vector() noexcept
+ { _M_init(); }
+
+ constexpr explicit
+ inplace_vector(size_type __n)
+ {
+ _M_init();
+ _S_reserve(__n);
+ std::uninitialized_value_construct_n(data(), __n);
+ _M_size = __n;
+ }
+
+ constexpr
+ inplace_vector(size_type __n, const _Tp& __value)
+ {
+ _M_init();
+ _S_reserve(__n);
+ std::uninitialized_fill_n(data(), __n, __value);
+ _M_size = __n;
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr
+ inplace_vector(_InputIterator __first, _InputIterator __last)
+ : inplace_vector()
+ {
+ if (const auto __n = _S_distance(__first, __last))
+ {
+ _S_reserve(__n);
+ std::uninitialized_copy(__first, __last, data());
+ _M_size = __n;
+ }
+ else
+ {
+ while (__first != __last)
+ emplace_back(*__first++);
+ }
+ }
+
+ template <__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr
+ inplace_vector(from_range_t, _Rg&& __rg)
+ : inplace_vector()
+ { append_range(__rg); }
+
+ constexpr
+ inplace_vector(initializer_list<_Tp> __il)
+ {
+ _M_init();
+ _S_reserve(__il.size());
+ std::uninitialized_copy(__il.begin(), __il.end(), data());
+ _M_size = __il.size();
+ }
+
+ inplace_vector(const inplace_vector&)
+ requires is_trivially_copy_constructible_v<_Tp>
+ = default;
+
+ constexpr
+ inplace_vector(const inplace_vector& __other)
+ noexcept(is_nothrow_copy_constructible_v<_Tp>)
+ {
+ _M_init();
+ std::uninitialized_copy(__other.begin(), __other.end(), data());
+ _M_size = __other.size();
+ }
+
+ inplace_vector(inplace_vector&&)
+ requires is_trivially_move_constructible_v<_Tp>
+ = default;
+
+ constexpr
+ inplace_vector(inplace_vector&& __other)
+ noexcept(is_nothrow_move_constructible_v<_Tp>)
+ {
+ _M_init();
+ std::uninitialized_move(__other.begin(), __other.end(), data());
+ _M_size = __other.size();
+ }
+
+ ~inplace_vector()
+ requires is_trivially_destructible_v<_Tp>
+ = default;
+
+ constexpr
+ ~inplace_vector()
+ { clear(); }
+
+ inplace_vector&
+ operator=(const inplace_vector&)
+ requires is_trivially_copy_assignable_v<_Tp>
+ && is_trivially_copy_constructible_v<_Tp>
+ && is_trivially_destructible_v<_Tp>
+ = default;
+
+ constexpr inplace_vector&
+ operator=(const inplace_vector& __other)
+ noexcept(is_nothrow_copy_assignable_v<_Tp>
+ && is_nothrow_copy_constructible_v<_Tp>)
+ {
+ if (std::addressof(__other) != this) [[likely]]
+ assign(__other.begin(), __other.end());
+ return *this;
+ }
+
+ inplace_vector&
+ operator=(inplace_vector&&)
+ requires is_trivially_move_assignable_v<_Tp>
+ && is_trivially_move_constructible_v<_Tp>
+ && is_trivially_destructible_v<_Tp>
+ = default;
+
+ constexpr inplace_vector&
+ operator=(inplace_vector&& __other)
+ noexcept(is_nothrow_move_assignable_v<_Tp>
+ && is_nothrow_move_constructible_v<_Tp>)
+ {
+ if (std::addressof(__other) != this) [[likely]]
+ assign(std::make_move_iterator(__other.begin()),
+ std::make_move_iterator(__other.end()));
+ return *this;
+ }
+
+ constexpr inplace_vector&
+ operator=(initializer_list<_Tp> __il)
+ {
+ assign(__il.begin(), __il.end());
+ return *this;
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr void
+ assign(_InputIterator __first, _InputIterator __last)
+ {
+ if (const auto __n = _S_distance(__first, __last))
+ {
+ _S_reserve(__n);
+ if (_M_size <= __n)
+ {
+ for (size_t __i = 0; __i < _M_size; ++__i, (void)++__first)
+ _M_elems[__i] = *__first;
+ std::uninitialized_copy(__first, __last, end());
+ }
+ else
+ std::destroy(std::copy(__first, __last, begin()), end());
+ _M_size = __n;
+ }
+ else
+ {
+ size_t __i = 0;
+ for (;__first != __last && __i < _M_size; ++__first)
+ _M_elems[__i++] = *__first;
+ if (__first == __last)
+ {
+ std::_Destroy_n(data() + __i, _M_size - __i);
+ _M_size = __i;
+ }
+ else
+ {
+ while (__first != __last)
+ emplace_back(*__first++);
+ }
+ }
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ assign_range(_Rg&& __rg)
+ {
+ if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
+ {
+ const auto __sz = ranges::distance(__rg);
+ if (__sz > _Nm)
+ __throw_bad_alloc();
+ if (__sz <= size())
+ {
+ ranges::copy_n(ranges::begin(__rg), __sz, data());
+ std::destroy(data() + __sz, data() + _M_size);
+ }
+ else
+ {
+ auto [__in, __out] = ranges::copy_n(
+ ranges::begin(__rg), _M_size,
+ data());
+ ranges::uninitialized_copy(
+ std::move(__in), ranges::end(__rg),
+ __out, unreachable_sentinel);
+ }
+ _M_size = __sz;
+ }
+ else
+ {
+ auto __in = ranges::begin(__rg);
+ auto __end = ranges::end(__rg);
+ size_type __n = 0;
+ for (; __n < _M_size && __in != __end; ++__in)
+ _M_elems[__n++] = *__in;
+
+ if (__in == __end)
+ {
+ std::destroy(data() + __n, data() + _M_size);
+ _M_size = __n;
+ return;
+ }
+ else if (__n < _Nm)
+ {
+ auto __res = ranges::uninitialized_copy(
+ std::move(__in), __end,
+ data() + __n, data() + _Nm);
+ _M_size = __res.out - data();
+ if (__res.in == ranges::end(__rg))
+ return;
+ }
+ __throw_bad_alloc();
+ }
+ }
+
+ constexpr void
+ assign(size_type __n, const _Tp& __u)
+ {
+ _S_reserve(__n);
+ if (_M_size <= __n)
+ std::uninitialized_fill_n(std::fill_n(data(), _M_size, __u),
+ __n - _M_size, __u);
+ else
+ std::destroy_n(std::fill_n(data(), __n, __u), _M_size - __n);
+ _M_size = __n;
+ }
+
+ constexpr void
+ assign(initializer_list<_Tp> __il)
+ { assign(__il.begin(), __il.end()); }
+
+ // iterators
+ [[nodiscard]]
+ constexpr iterator
+ begin() noexcept { return iterator(data()); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ begin() const noexcept { return const_iterator(data()); }
+
+ [[nodiscard]]
+ constexpr iterator
+ end() noexcept
+ { return iterator(data() + _M_size); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ end() const noexcept
+ { return const_iterator(data() + _M_size); }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rbegin() noexcept
+ { return reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rbegin() const noexcept
+ { return const_reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rend() noexcept { return reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rend() const noexcept { return const_reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cbegin() const noexcept { return begin(); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cend() const noexcept { return end(); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crbegin() const noexcept { return rbegin(); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crend() const noexcept { return rend(); }
+
+ // [containers.sequences.inplace.vector.members] size/capacity
+ [[nodiscard]]
+ constexpr bool
+ empty() const noexcept { return _M_size == 0; }
+
+ [[nodiscard]]
+ constexpr size_type
+ size() const noexcept
+ {
+ if (_M_size > _Nm)
+ __builtin_unreachable();
+ return _M_size;
+ }
+
+ [[nodiscard]]
+ static constexpr size_type
+ max_size() noexcept { return _Nm; }
+
+ [[nodiscard]]
+ static constexpr size_type
+ capacity() noexcept { return _Nm; }
+
+ constexpr void
+ resize(size_type __n)
+ {
+ _S_reserve(__n);
+ if (__n > _M_size)
+ std::uninitialized_value_construct_n(data() + _M_size, __n - _M_size);
+ else if (__n < _M_size)
+ std::destroy_n(data() + __n, _M_size - __n);
+ _M_size = __n;
+ }
+
+ constexpr void
+ resize(size_type __n, const _Tp& __c)
+ {
+ _S_reserve(__n);
+ if (__n > _M_size)
+ std::uninitialized_fill_n(data() + _M_size, __n - _M_size, __c);
+ else if (__n < _M_size)
+ std::destroy_n(data() + __n, _M_size - __n);
+ _M_size = __n;
+ }
+
+ static constexpr void
+ reserve(size_type __n)
+ { _S_reserve(__n); }
+
+ static constexpr void
+ shrink_to_fit() { }
+
+ // element access
+ [[nodiscard]]
+ constexpr reference
+ operator[](size_type __n)
+ {
+ __glibcxx_requires_subscript(__n);
+ return _M_elems[__n];
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ operator[](size_type __n) const
+ {
+ __glibcxx_requires_subscript(__n);
+ return _M_elems[__n];
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ at(size_type __n) const
+ {
+ if (__n >= _M_size)
+ std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
+ "(which is %zu) "
+ ">= size() (which is %zu)"),
+ __n, _M_size);
+ return _M_elems[__n];
+ }
+
+ [[nodiscard]]
+ constexpr reference
+ at(size_type __n)
+ {
+ if (__n >= _M_size)
+ std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
+ "(which is %zu) "
+ ">= size() (which is %zu)"),
+ __n, _M_size);
+ return _M_elems[__n];
+ }
+
+ [[nodiscard]]
+ constexpr reference
+ front()
+ {
+ __glibcxx_requires_nonempty();
+ return _M_elems[0];
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ front() const
+ {
+ __glibcxx_requires_nonempty();
+ return _M_elems[0];
+ }
+
+ [[nodiscard]]
+ constexpr reference
+ back()
+ {
+ __glibcxx_requires_nonempty();
+ return _M_elems[_M_size - 1];
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ back() const
+ {
+ __glibcxx_requires_nonempty();
+ return _M_elems[_M_size - 1];
+ }
+
+ // [containers.sequences.inplace.vector.data], data access
+
+ [[nodiscard]]
+ constexpr _Tp*
+ data() noexcept
+ { return static_cast<pointer>(_M_elems); }
+
+ [[nodiscard]]
+ constexpr const _Tp*
+ data() const noexcept
+ { return static_cast<const_pointer>(_M_elems); }
+
+ // [containers.sequences.inplace.vector.modifiers], modifiers
+ template<typename... _Args>
+ constexpr _Tp&
+ emplace_back(_Args&&... __args)
+ {
+ if (_M_size >= _Nm)
+ __throw_bad_alloc();
+ return unchecked_emplace_back(std::forward<_Args>(__args)...);
+ }
+
+ constexpr _Tp&
+ push_back(const _Tp& __x)
+ { return emplace_back(__x); }
+
+ constexpr _Tp&
+ push_back(_Tp&& __x)
+ { return emplace_back(std::move(__x)); }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ append_range(_Rg&& __rg)
+ {
+ if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
+ {
+ const auto __sz = ranges::distance(__rg);
+ if (__sz > (_Nm - size()))
+ __throw_bad_alloc();
+ // Bounded on output range due PR121143
+ ranges::uninitialized_copy(
+ ranges::begin(__rg), unreachable_sentinel,
+ data() + _M_size, data() + _M_size + __sz);
+ _M_size += size_type(__sz);
+ }
+ else
+ {
+ ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm);
+ auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail);
+ _M_size = __out - data();
+ if (__in != ranges::end(__rg))
+ __throw_bad_alloc();
+ }
+ }
+
+ constexpr void
+ pop_back()
+ {
+ __glibcxx_requires_nonempty();
+ --_M_size;
+ _M_elems[_M_size].~_Tp();
+ }
+
+ template<typename... _Args>
+ constexpr _Tp*
+ try_emplace_back(_Args&&... __args)
+ {
+ if (_M_size >= _Nm) [[unlikely]]
+ return nullptr;
+ auto& __r = unchecked_emplace_back(std::forward<_Args>(__args)...);
+ return __builtin_addressof(__r);
+ }
+
+ constexpr _Tp*
+ try_push_back(const _Tp& __x)
+ {
+ if (_M_size >= _Nm) [[unlikely]]
+ return nullptr;
+ return __builtin_addressof(unchecked_emplace_back(__x));
+ }
+
+ constexpr _Tp*
+ try_push_back(_Tp&& __x)
+ {
+ if (_M_size >= _Nm) [[unlikely]]
+ return nullptr;
+ return __builtin_addressof(unchecked_emplace_back(std::move(__x)));
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr ranges::borrowed_iterator_t<_Rg>
+ try_append_range(_Rg&& __rg)
+ {
+ if constexpr (ranges::sized_range<_Rg>)
+ {
+ auto __n = ranges::distance(__rg);
+ if (__n == 0) [[unlikely]]
+ return ranges::begin(__rg);
+
+ const auto __end = data() + _M_size;
+ const size_t __avail = _Nm - size();
+ if (__n <= __avail)
+ _M_size += size_type(__n);
+ else
+ {
+ __n = __avail;
+ _M_size = _Nm;
+ }
+ return ranges::uninitialized_copy_n(
+ ranges::begin(__rg), __n,
+ __end, unreachable_sentinel).in;
+ }
+ else
+ {
+ ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm);
+ auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail);
+ _M_size = __out - data();
+ return std::move(__in);
+ }
+ }
+
+ template<typename... _Args>
+ constexpr _Tp&
+ unchecked_emplace_back(_Args&&... __args)
+ {
+ __glibcxx_assert(_M_size < _Nm);
+ auto __p = std::construct_at(data() + _M_size,
+ std::forward<_Args>(__args)...);
+ ++_M_size;
+ return *__p;
+ }
+
+ constexpr _Tp&
+ unchecked_push_back(const _Tp& __x)
+ { return unchecked_emplace_back(__x); }
+
+ constexpr _Tp&
+ unchecked_push_back(_Tp&& __x)
+ { return unchecked_emplace_back(std::move(__x)); }
+
+ template<typename... _Args>
+ constexpr iterator
+ emplace(const_iterator __position, _Args&&... __args)
+ {
+ size_t __b = __position - cbegin(); // elements before position
+ __glibcxx_assert(__b <= _M_size);
+ if (_M_size >= _Nm)
+ __throw_bad_alloc();
+ iterator __pos = begin() + __b;
+ std::construct_at(data() + _M_size, std::forward<_Args>(__args)...);
+ if (_M_size++)
+ std::rotate(__pos, end() - 1, end());
+ return __pos;
+ }
+
+ constexpr iterator
+ insert(const_iterator __position, const _Tp& __x)
+ { return emplace(__position, __x); }
+
+ constexpr iterator
+ insert(const_iterator __position, _Tp&& __x)
+ { return emplace(__position, std::move(__x)); }
+
+ constexpr iterator
+ insert(const_iterator __position, size_type __n, const _Tp& __x)
+ {
+ size_t __b = __position - cbegin(); // elements before position
+ __glibcxx_assert(__b <= _M_size);
+ if ((_Nm - _M_size) < __n)
+ __throw_bad_alloc();
+ iterator __pos = begin() + __b;
+ std::uninitialized_fill_n(data() + _M_size, __n, __x);
+ if (std::__exchange(_M_size, _M_size + __n))
+ std::rotate(__pos, end() - __n, end());
+ return __pos;
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr iterator
+ insert(const_iterator __position, _InputIterator __first,
+ _InputIterator __last)
+ {
+ size_t __b = __position - cbegin(); // elements before position
+ __glibcxx_assert(__b <= _M_size);
+ iterator __pos = begin() + __b;
+ const size_t __s = _M_size;
+ if (const auto __n = _S_distance(__first, __last))
+ {
+ if ((_Nm - _M_size) < __n)
+ __throw_bad_alloc();
+ std::uninitialized_copy(__first, __last, data() + _M_size);
+ _M_size += __n;
+ }
+ else
+ {
+ while (__first != __last)
+ emplace_back(*__first++);
+ }
+ if (__s)
+ std::rotate(__pos, begin() + __s, end());
+ return __pos;
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr iterator
+ insert_range(const_iterator __position, _Rg&& __rg)
+ {
+ iterator __pos = begin() + (__position - cbegin());
+ const auto __end = end();
+ if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
+ {
+ const auto __len = ranges::distance(__rg);
+ if (__len > (_Nm - size()))
+ __throw_bad_alloc();
+ if (!__len) [[unlikely]]
+ return __pos;
+
+ const size_type __n = size_type(__len);
+ const size_type __num_after = __end - __pos;
+ if (__num_after >= __n)
+ {
+ ranges::uninitialized_move(__end - __n, __end,
+ __end, unreachable_sentinel);
+ _M_size += __n;
+ ranges::move_backward(__pos, __end - __n, __end);
+ ranges::copy(__rg, __pos);
+ }
+ else if constexpr (ranges::forward_range<_Rg>)
+ {
+ auto __mid = ranges::next(ranges::begin(__rg), __num_after);
+ ranges::uninitialized_copy(__mid, ranges::end(__rg),
+ __end, unreachable_sentinel);
+ _M_size += __n - __num_after;
+ ranges::uninitialized_move(__pos, __end,
+ __pos + __n, unreachable_sentinel);
+ _M_size += __num_after;
+ ranges::copy(ranges::begin(__rg), __mid, __pos);
+ }
+ else
+ {
+ ranges::uninitialized_copy(
+ ranges::begin(__rg), ranges::end(__rg),
+ __end, unreachable_sentinel);
+ _M_size += __n;
+ std::rotate(__pos, __end, end());
+ }
+ }
+ else
+ {
+ append_range(__rg);
+ std::rotate(__pos, __end, end());
+ }
+ return __pos;
+ }
+
+ constexpr iterator
+ insert(const_iterator __position, initializer_list<_Tp> __il)
+ { return insert(__position, __il.begin(), __il.end()); }
+
+ constexpr iterator
+ erase(const_iterator __position)
+ {
+ size_t __n = __position - cbegin();
+ __glibcxx_assert(__n < _M_size);
+ iterator __pos = begin() + __n;
+ std::move(__pos + 1, end(), __pos);
+ pop_back();
+ return __pos;
+ }
+
+ constexpr iterator
+ erase(const_iterator __first, const_iterator __last)
+ {
+ size_t __n = __first - cbegin();
+ size_t __x = __last - __first;
+ __glibcxx_assert(__n <= _M_size);
+ __glibcxx_assert(__x <= _M_size);
+ iterator __pos = begin() + __n;
+ iterator __end = std::move(__pos + __x, end(), __pos);
+ std::destroy_n(__end, __x);
+ _M_size -= __x;
+ return __pos;
+ }
+
+ constexpr void
+ swap(inplace_vector& __x)
+ noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>)
+ {
+ inplace_vector* __vs[2]{ this, std::addressof(__x) };
+ const auto __smaller = __vs[__x.size() < size()];
+ const auto __bigger = __vs[__x.size() >= size()];
+ size_type __n = __smaller->size();
+ size_type __n2 = __bigger->size();
+
+ if constexpr (is_nothrow_move_constructible_v<_Tp>)
+ {
+ for (size_type __i = __n; __i < __n2; ++__i)
+ {
+ std::construct_at(__smaller->data() + __i,
+ std::move(*(__bigger->data() + __i)));
+ std::destroy_at(__bigger->data() + __i);
+ }
+ }
+ else
+ {
+ std::uninitialized_copy(__bigger->data() + __n,
+ __bigger->data() + __n2,
+ __smaller->data() + __n);
+ std::destroy(__bigger->data() + __n, __bigger->data() + __n2);
+ }
+ __smaller->_M_size = __n2;
+ __bigger->_M_size = __n;
+
+ using std::swap;
+ for (size_type __i = 0; __i < __n; __i++)
+ swap(_M_elems[__i], __x._M_elems[__i]);
+ }
+
+ constexpr void
+ clear() noexcept
+ {
+ std::destroy_n(data(), size_t(_M_size));
+ _M_size = 0;
+ }
+
+ constexpr friend bool
+ operator==(const inplace_vector& __x, const inplace_vector& __y)
+ { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); }
+
+ constexpr friend auto
+ operator<=>(const inplace_vector& __x, const inplace_vector& __y)
+ requires requires (const _Tp __t) {
+ { __t < __t } -> __detail::__boolean_testable;
+ }
+ {
+ return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
+ __y.begin(), __y.end(),
+ __detail::__synth3way);
+ }
+
+ // [inplace.vector.special], specialized algorithms
+ constexpr friend void
+ swap(inplace_vector& __x, inplace_vector& __y)
+ noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>)
+ { __x.swap(__y); }
+
+ private:
+ union {
+ _Tp _M_elems[_Nm];
+ };
+
+ // Check whether integer type _UInt is wide enough to store _Nm,
+ // so that we use a smaller type for _M_size when that saves space.
+ template<typename _UInt, bool = (alignof(_Tp) <= sizeof(_UInt))>
+ static constexpr bool __fits
+ = _Nm <= __gnu_cxx::__int_traits<_UInt>::__max;
+
+ // Don't bother using a smaller type if alignment of the array elements
+ // means that it doesn't actually save space.
+ template<typename _UInt>
+ static constexpr bool __fits<_UInt, false> = false;
+
+ static consteval auto __select_size_type()
+ {
+ if constexpr (__fits<unsigned char>)
+ return (unsigned char)0;
+#if __SHRT_WIDTH__ < __SIZE_WIDTH__
+ else if constexpr (__fits<unsigned short>)
+ return (unsigned short)0;
+#endif
+#if __INT_WIDTH__ < __SIZE_WIDTH__ && __INT_WIDTH__ > __SHRT_WIDTH__
+ else if constexpr (__fits<unsigned int>)
+ return 0u;
+#endif
+#if __LONG_WIDTH__ < __SIZE_WIDTH__ && __LONG_WIDTH__ > __INT_WIDTH__
+ else if constexpr (__fits<unsigned long>)
+ return 0ul;
+#endif
+ else // Just use size_t.
+ return 0uz;
+ }
+ decltype(__select_size_type()) _M_size = 0;
+
+ constexpr void
+ _M_init()
+ {
+ if !consteval
+ {
+#if __glibcxx_start_lifetime_as
+ std::start_lifetime_as_array<_Tp>(data(), _Nm);
+#endif
+ }
+ else
+ {
+ // TODO: use new(_M_elems) _Tp[_Nm]() once PR121068 is fixed
+ if constexpr (is_trivial_v<_Tp>)
+ for (size_t __i = 0; __i < _Nm; ++__i)
+ _M_elems[__i] = _Tp();
+ else
+ __builtin_unreachable(); // only trivial types are supported at compile time
+ }
+ }
+
+ static constexpr void
+ _S_reserve(size_t __n)
+ {
+ if (__n > _Nm)
+ __throw_bad_alloc();
+ }
+
+ template<typename _InputIterator>
+ constexpr static auto
+ _S_distance(_InputIterator __first, _InputIterator __last)
+ {
+ if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>
+ || forward_iterator<_InputIterator>)
+ return (size_type)ranges::distance(__first, __last);
+ else if constexpr (derived_from<__iter_category_t<_InputIterator>,
+ forward_iterator_tag>)
+ return (size_type)std::distance(__first, __last);
+ else
+ return false_type{};
+ }
+ };
+
+ // specialization for zero capacity, that is required to be trivally copyable
+ // and empty regardless of _Tp.
+ template<typename _Tp>
+ class inplace_vector<_Tp, 0>
+ {
+ public:
+ // types:
+ using value_type = _Tp;
+ using pointer = _Tp*;
+ using const_pointer = const _Tp*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using iterator
+ = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>;
+ using const_iterator
+ = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // [containers.sequences.inplace.vector.cons], construct/copy/destroy
+ inplace_vector() = default;
+
+ constexpr explicit
+ inplace_vector(size_type __n)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ constexpr
+ inplace_vector(size_type __n, const _Tp& __value)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr
+ inplace_vector(_InputIterator __first, _InputIterator __last)
+ {
+ if (__first != __last)
+ __throw_bad_alloc();
+ }
+
+ template <__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr
+ inplace_vector(from_range_t, _Rg&& __rg)
+ {
+ if (ranges::begin(__rg) != ranges::end(__rg))
+ __throw_bad_alloc();
+ }
+
+ constexpr
+ inplace_vector(initializer_list<_Tp> __il)
+ {
+ if (__il.size() != 0)
+ __throw_bad_alloc();
+ }
+
+ inplace_vector(const inplace_vector&) = default;
+ inplace_vector(inplace_vector&&) = default;
+
+ constexpr
+ ~inplace_vector() = default;
+
+ inplace_vector&
+ operator=(const inplace_vector&) = default;
+
+ inplace_vector&
+ operator=(inplace_vector&&) = default;
+
+ constexpr inplace_vector&
+ operator=(initializer_list<_Tp> __il)
+ {
+ if (__il.size() != 0)
+ __throw_bad_alloc();
+ return *this;
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr void
+ assign(_InputIterator __first, _InputIterator __last)
+ {
+ if (__first != __last)
+ __throw_bad_alloc();
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ assign_range(_Rg&& __rg)
+ {
+ if (ranges::begin(__rg) != ranges::end(__rg))
+ __throw_bad_alloc();
+ }
+
+ constexpr void
+ assign(size_type __n, const _Tp& __u)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ constexpr void
+ assign(initializer_list<_Tp> __il)
+ {
+ if (__il.size() != 0)
+ __throw_bad_alloc();
+ }
+
+ // iterators
+ [[nodiscard]]
+ constexpr iterator
+ begin() noexcept { return iterator(nullptr); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ begin() const noexcept { return const_iterator(nullptr); }
+
+ [[nodiscard]]
+ constexpr iterator
+ end() noexcept { return iterator(nullptr); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ end() const noexcept { return const_iterator(nullptr); }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rbegin() noexcept
+ { return reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rbegin() const noexcept
+ { return const_reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rend() noexcept { return reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rend() const noexcept { return const_reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cbegin() const noexcept { return begin(); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cend() const noexcept { return end(); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crbegin() const noexcept { return rbegin(); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crend() const noexcept { return rend(); }
+
+ // [containers.sequences.inplace.vector.members] size/capacity
+ [[nodiscard]]
+ constexpr bool
+ empty() const noexcept { return true; }
+
+ [[nodiscard]]
+ constexpr size_type
+ size() const noexcept { return 0; }
+
+ [[nodiscard]]
+ static constexpr size_type
+ max_size() noexcept { return 0; }
+
+ [[nodiscard]]
+ static constexpr size_type
+ capacity() noexcept { return 0; }
+
+ constexpr void
+ resize(size_type __n)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ constexpr void
+ resize(size_type __n, const _Tp&)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ static constexpr void
+ reserve(size_type __n)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ static constexpr void
+ shrink_to_fit() { }
+
+ // element access
+ [[nodiscard,noreturn]]
+ constexpr reference
+ operator[](size_type)
+ { __builtin_trap(); }
+
+ [[nodiscard,noreturn]]
+ constexpr const_reference
+ operator[](size_type) const
+ { __builtin_trap(); }
+
+ [[nodiscard,noreturn]]
+ constexpr const_reference
+ at(size_type __n) const
+ {
+ std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
+ "(which is %zu) "
+ ">= size() (which is 0)"),
+ __n);
+ }
+
+ [[nodiscard,noreturn]]
+ constexpr reference
+ at(size_type __n)
+ {
+ std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
+ "(which is %zu) "
+ ">= size() (which is 0)"),
+ __n);
+ }
+
+ [[nodiscard,noreturn]]
+ constexpr reference
+ front()
+ { __builtin_trap(); }
+
+ [[nodiscard,noreturn]]
+ constexpr const_reference
+ front() const
+ { __builtin_trap(); }
+
+ [[nodiscard,noreturn]]
+ constexpr reference
+ back()
+ { __builtin_trap(); }
+
+ [[nodiscard,noreturn]]
+ constexpr const_reference
+ back() const
+ { __builtin_trap(); }
+
+ // [containers.sequences.inplace.vector.data], data access
+
+ [[nodiscard]]
+ constexpr _Tp*
+ data() noexcept
+ { return nullptr; }
+
+ [[nodiscard]]
+ constexpr const _Tp*
+ data() const noexcept
+ { return nullptr; }
+
+ // [containers.sequences.inplace.vector.modifiers], modifiers
+ template<typename... _Args>
+ [[noreturn]]
+ constexpr _Tp&
+ emplace_back(_Args&&...)
+ { __throw_bad_alloc(); }
+
+ [[noreturn]]
+ constexpr _Tp&
+ push_back(const _Tp&)
+ { __throw_bad_alloc(); }
+
+ [[noreturn]]
+ constexpr _Tp&
+ push_back(_Tp&&)
+ { __throw_bad_alloc(); }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ append_range(_Rg&& __rg)
+ {
+ if (ranges::begin(__rg) != ranges::end(__rg))
+ __throw_bad_alloc();
+ }
+
+ [[noreturn]]
+ constexpr void
+ pop_back()
+ { __builtin_trap(); }
+
+ template<typename... _Args>
+ constexpr _Tp*
+ try_emplace_back(_Args&&...)
+ { return nullptr; }
+
+ constexpr _Tp*
+ try_push_back(const _Tp&)
+ { return nullptr; }
+
+ constexpr _Tp*
+ try_push_back(_Tp&&)
+ { return nullptr; }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr ranges::borrowed_iterator_t<_Rg>
+ try_append_range(_Rg&& __rg)
+ { return ranges::begin(__rg); }
+
+ template<typename... _Args>
+ [[noreturn]]
+ constexpr _Tp&
+ unchecked_emplace_back(_Args&&...)
+ { __builtin_trap(); }
+
+ [[noreturn]]
+ constexpr _Tp&
+ unchecked_push_back(const _Tp&)
+ { __builtin_trap(); }
+
+ [[noreturn]]
+ constexpr _Tp&
+ unchecked_push_back(_Tp&&)
+ { __builtin_trap(); }
+
+ template<typename... _Args>
+ [[noreturn]]
+ constexpr iterator
+ emplace(const_iterator, _Args&&...)
+ { __throw_bad_alloc(); }
+
+ [[noreturn]]
+ constexpr iterator
+ insert(const_iterator, const _Tp&)
+ { __throw_bad_alloc(); }
+
+ [[noreturn]]
+ constexpr iterator
+ insert(const_iterator, _Tp&&)
+ { __throw_bad_alloc(); }
+
+ constexpr iterator
+ insert(const_iterator, size_type __n, const _Tp&)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ return begin();
+ }
+
+ template<typename _InputIterator>
+ constexpr iterator
+ insert(const_iterator, _InputIterator __first, _InputIterator __last)
+ {
+ if (__first != __last)
+ __throw_bad_alloc();
+ return begin();
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr iterator
+ insert_range(const_iterator, _Rg&& __rg)
+ {
+ if (ranges::begin(__rg) != ranges::end(__rg))
+ __throw_bad_alloc();
+ return begin();
+ }
+
+ constexpr iterator
+ insert(const_iterator, initializer_list<_Tp> __il)
+ {
+ if (__il.size() != 0)
+ __throw_bad_alloc();
+ return begin();
+ }
+
+ [[noreturn]]
+ constexpr iterator
+ erase(const_iterator)
+ { __builtin_trap(); }
+
+ constexpr iterator
+ erase(const_iterator __first, const_iterator __last)
+ {
+ __glibcxx_assert(__first == __last);
+ return begin();
+ }
+
+ constexpr void
+ swap(inplace_vector& __x)
+ noexcept
+ { }
+
+ constexpr void
+ clear() noexcept
+ { }
+
+ constexpr friend bool
+ operator==(const inplace_vector&, const inplace_vector&)
+ { return true; }
+
+ constexpr friend auto
+ operator<=>(const inplace_vector&, const inplace_vector&)
+ requires requires (const _Tp __t) {
+ { __t < __t } -> __detail::__boolean_testable;
+ }
+ { return std::strong_ordering::equal; }
+
+ // n.b. there is not explicit wording requiring that swap for inplace_vector,
+ // with zero size, works even if element type is not swappable. However given
+ // that move operations are required to be present and trivial, it makes sense
+ // to support them.
+ constexpr friend void
+ swap(inplace_vector&, inplace_vector&) noexcept
+ { }
+ };
+
+_GLIBCXX_END_NAMESPACE_CONTAINER
+
+ template<typename _Tp, size_t _Nm, typename _Predicate>
+ constexpr size_t
+ erase_if(_GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __cont,
+ _Predicate __pred)
+ {
+ if constexpr (_Nm != 0)
+ {
+ const auto __osz = __cont.size();
+ const auto __end = __cont.end();
+ auto __removed = std::__remove_if(__cont.begin(), __end,
+ std::move(__pred));
+ if (__removed != __end)
+ {
+ __cont.erase(__removed, __end);
+ return __osz - __cont.size();
+ }
+ }
+
+ return 0;
+ }
+
+ template<typename _Tp, size_t _Nm, typename _Up = _Tp>
+ constexpr size_t
+ erase(_GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __cont, const _Up& __value)
+ { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+
+#ifdef _GLIBCXX_DEBUG
+# include <debug/inplace_vector>
+#endif
+
+#endif // __glibcxx_inplace_vector
+#endif // _GLIBCXX_INPLACE_VECTOR
diff --git a/libstdc++-v3/include/std/istream b/libstdc++-v3/include/std/istream
index d5bb187..ea232a7 100644
--- a/libstdc++-v3/include/std/istream
+++ b/libstdc++-v3/include/std/istream
@@ -42,6 +42,10 @@
#include <ios>
#include <ostream>
+#if __cplusplus > 202302L
+#include <concepts>
+#endif
+
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -537,7 +541,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* is extracted); note that this condition will never occur if
* @a __delim equals @c traits::eof().
*
- * NB: Provide three overloads, instead of the single function
+ * NB: Provide four overloads, instead of the single function
* (with defaults) mandated by the Standard: this leads to a
* better performing implementation, while still conforming to
* the Standard.
@@ -551,6 +555,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__istream_type&
ignore();
+#if __cplusplus > 202302L
+ [[__gnu__::__always_inline__]]
+ __istream_type&
+ ignore(streamsize __n, char __delim) requires same_as<_CharT, char>
+ { return ignore(__n, traits_type::to_int_type(__delim)); }
+#endif
+
/**
* @brief Looking ahead in the stream
* @return The next character, or eof().
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
index cf64854..df126c6 100644
--- a/libstdc++-v3/include/std/latch
+++ b/libstdc++-v3/include/std/latch
@@ -41,7 +41,7 @@
#ifdef __cpp_lib_latch // C++ >= 20 && atomic_wait
#include <bits/atomic_base.h>
#include <ext/numeric_traits.h>
-#include <utility> // cmp_equal, cmp_less_equal, etc.
+#include <bits/intcmp.h> // cmp_equal, cmp_less_equal, etc.
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -62,7 +62,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr explicit
latch(ptrdiff_t __expected) noexcept
- : _M_a(__expected)
+ : _M_counter(__expected)
{ __glibcxx_assert(__expected >= 0 && __expected <= max()); }
~latch() = default;
@@ -74,35 +74,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
count_down(ptrdiff_t __update = 1)
{
__glibcxx_assert(__update >= 0 && __update <= max());
- auto const __old = __atomic_impl::fetch_sub(&_M_a, __update,
+ auto const __old = __atomic_impl::fetch_sub(&_M_counter, __update,
memory_order::release);
if (std::cmp_equal(__old, __update))
- __atomic_impl::notify_all(&_M_a);
+ __atomic_impl::notify_all(&_M_counter);
else
__glibcxx_assert(std::cmp_less(__update, __old));
}
_GLIBCXX_ALWAYS_INLINE bool
try_wait() const noexcept
- { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+ { return __atomic_impl::load(&_M_counter, memory_order::acquire) == 0; }
_GLIBCXX_ALWAYS_INLINE void
wait() const noexcept
{
- auto const __pred = [this] { return this->try_wait(); };
- std::__atomic_wait_address(&_M_a, __pred);
+ auto const __vfn = [this] {
+ return __atomic_impl::load(&_M_counter, memory_order::acquire);
+ };
+ auto const __pred = [](__detail::__platform_wait_t __v) {
+ return __v == 0;
+ };
+ std::__atomic_wait_address(&_M_counter, __pred, __vfn);
}
_GLIBCXX_ALWAYS_INLINE void
arrive_and_wait(ptrdiff_t __update = 1) noexcept
{
- count_down(__update);
- wait();
+ // The standard specifies this functions as count_down(update); wait();
+ // but we combine those two calls into one and avoid the wait() if we
+ // know the counter reached zero.
+
+ __glibcxx_assert(__update >= 0 && __update <= max());
+ // Use acq_rel here because an omitted wait() would have used acquire:
+ auto const __old = __atomic_impl::fetch_sub(&_M_counter, __update,
+ memory_order::acq_rel);
+ if (std::cmp_equal(__old, __update))
+ __atomic_impl::notify_all(&_M_counter);
+ else
+ {
+ __glibcxx_assert(std::cmp_less(__update, __old));
+ wait();
+ }
}
private:
alignas(__detail::__platform_wait_alignment)
- __detail::__platform_wait_t _M_a;
+ __detail::__platform_wait_t _M_counter;
};
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
diff --git a/libstdc++-v3/include/std/limits b/libstdc++-v3/include/std/limits
index 2331c25..49ce7c9 100644
--- a/libstdc++-v3/include/std/limits
+++ b/libstdc++-v3/include/std/limits
@@ -1639,7 +1639,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#define __INT_N_U201103(TYPE)
#endif
-#if !defined(__STRICT_ANSI__)
#ifdef __GLIBCXX_TYPE_INT_N_0
__INT_N(__GLIBCXX_TYPE_INT_N_0, __GLIBCXX_BITSIZE_INT_N_0,
__INT_N_201103 (__GLIBCXX_TYPE_INT_N_0),
@@ -1661,7 +1660,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__INT_N_U201103 (__GLIBCXX_TYPE_INT_N_3))
#endif
-#elif defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
+#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
__INT_N(__int128, 128,
__INT_N_201103 (__int128),
__INT_N_U201103 (__int128))
@@ -2129,7 +2128,7 @@ __glibcxx_float_n(128)
static _GLIBCXX_USE_CONSTEXPR int digits = 113;
static _GLIBCXX_USE_CONSTEXPR int digits10 = 33;
#if __cplusplus >= 201103L
- static constexpr int max_digits10 = 35;
+ static constexpr int max_digits10 = 36;
#endif
static _GLIBCXX_USE_CONSTEXPR bool is_signed = true;
static _GLIBCXX_USE_CONSTEXPR bool is_integer = false;
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
new file mode 100644
index 0000000..dc0aa4f
--- /dev/null
+++ b/libstdc++-v3/include/std/mdspan
@@ -0,0 +1,3399 @@
+// <mdspan> -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file mdspan
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_MDSPAN
+#define _GLIBCXX_MDSPAN 1
+
+#ifdef _GLIBCXX_SYSHDR
+#pragma GCC system_header
+#endif
+
+#include <span>
+#include <array>
+#include <type_traits>
+#include <utility>
+
+#define __glibcxx_want_mdspan
+#define __glibcxx_want_aligned_accessor
+#define __glibcxx_want_submdspan
+#include <bits/version.h>
+
+#if __glibcxx_aligned_accessor
+#include <bits/align.h>
+#endif
+
+#if __glibcxx_submdspan
+#include <tuple>
+#endif
+
+
+#ifdef __glibcxx_mdspan
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ namespace __mdspan
+ {
+ consteval bool
+ __all_static(std::span<const size_t> __extents)
+ {
+ for(auto __ext : __extents)
+ if (__ext == dynamic_extent)
+ return false;
+ return true;
+ }
+
+ consteval bool
+ __all_dynamic(std::span<const size_t> __extents)
+ {
+ for(auto __ext : __extents)
+ if (__ext != dynamic_extent)
+ return false;
+ return true;
+ }
+
+ template<typename _IndexType, typename _OIndexType>
+ constexpr _IndexType
+ __index_type_cast(_OIndexType&& __other)
+ {
+ if constexpr (std::is_integral_v<_OIndexType>)
+ {
+ constexpr _IndexType __index_type_max
+ = __gnu_cxx::__int_traits<_IndexType>::__max;
+ constexpr _OIndexType __oindex_type_max
+ = __gnu_cxx::__int_traits<_OIndexType>::__max;
+
+ if constexpr (__index_type_max < __oindex_type_max)
+ __glibcxx_assert(cmp_less_equal(__other, __index_type_max));
+
+ if constexpr (std::is_signed_v<_OIndexType>)
+ __glibcxx_assert(__other >= 0);
+ return static_cast<_IndexType>(__other);
+ }
+ else
+ {
+ auto __ret = static_cast<_IndexType>(std::move(__other));
+ if constexpr (std::is_signed_v<_IndexType>)
+ __glibcxx_assert(__ret >= 0);
+ return __ret;
+ }
+ }
+
+ template<array _Extents>
+ class _StaticExtents
+ {
+ public:
+ static constexpr size_t _S_rank = _Extents.size();
+
+ // For __r in [0, _S_rank], _S_dynamic_index(__r) is the number
+ // of dynamic extents up to (and not including) __r.
+ //
+ // If __r is the index of a dynamic extent, then
+ // _S_dynamic_index[__r] is the index of that extent in
+ // _M_dyn_exts.
+ static constexpr size_t
+ _S_dynamic_index(size_t __r) noexcept
+ { return _S_dynamic_index_data[__r]; }
+
+ static constexpr auto _S_dynamic_index_data = [] consteval
+ {
+ array<size_t, _S_rank+1> __ret;
+ size_t __dyn = 0;
+ for (size_t __i = 0; __i < _S_rank; ++__i)
+ {
+ __ret[__i] = __dyn;
+ __dyn += (_Extents[__i] == dynamic_extent);
+ }
+ __ret[_S_rank] = __dyn;
+ return __ret;
+ }();
+
+ static constexpr size_t _S_rank_dynamic = _S_dynamic_index(_S_rank);
+
+ // For __r in [0, _S_rank_dynamic), _S_dynamic_index_inv(__r) is the
+ // index of the __r-th dynamic extent in _Extents.
+ static constexpr size_t
+ _S_dynamic_index_inv(size_t __r) noexcept
+ { return _S_dynamic_index_inv_data[__r]; }
+
+ static constexpr auto _S_dynamic_index_inv_data = [] consteval
+ {
+ array<size_t, _S_rank_dynamic> __ret;
+ for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i)
+ if (_Extents[__i] == dynamic_extent)
+ __ret[__r++] = __i;
+ return __ret;
+ }();
+
+ static constexpr size_t
+ _S_static_extent(size_t __r) noexcept
+ { return _Extents[__r]; }
+ };
+
+ template<array _Extents>
+ requires (__all_dynamic<_Extents>())
+ class _StaticExtents<_Extents>
+ {
+ public:
+ static constexpr size_t _S_rank = _Extents.size();
+
+ static constexpr size_t
+ _S_dynamic_index(size_t __r) noexcept
+ { return __r; }
+
+ static constexpr size_t _S_rank_dynamic = _S_rank;
+
+ static constexpr size_t
+ _S_dynamic_index_inv(size_t __k) noexcept
+ { return __k; }
+
+ static constexpr size_t
+ _S_static_extent(size_t) noexcept
+ { return dynamic_extent; }
+ };
+
+ template<typename _IndexType, array _Extents>
+ class _ExtentsStorage : public _StaticExtents<_Extents>
+ {
+ private:
+ using _Base = _StaticExtents<_Extents>;
+
+ public:
+ using _Base::_S_rank;
+ using _Base::_S_rank_dynamic;
+ using _Base::_S_dynamic_index;
+ using _Base::_S_dynamic_index_inv;
+ using _Base::_S_static_extent;
+
+ static constexpr bool
+ _S_is_dynamic(size_t __r) noexcept
+ {
+ if constexpr (__all_static(_Extents))
+ return false;
+ else if constexpr (__all_dynamic(_Extents))
+ return true;
+ else
+ return _Extents[__r] == dynamic_extent;
+ }
+
+ template<typename _OIndexType>
+ static constexpr _IndexType
+ _S_int_cast(const _OIndexType& __other) noexcept
+ { return _IndexType(__other); }
+
+ constexpr _IndexType
+ _M_extent(size_t __r) const noexcept
+ {
+ if (_S_is_dynamic(__r))
+ return _M_dyn_exts[_S_dynamic_index(__r)];
+ else
+ return _S_static_extent(__r);
+ }
+
+ template<size_t _OtherRank, typename _GetOtherExtent>
+ static constexpr bool
+ _S_is_compatible_extents(_GetOtherExtent __get_extent) noexcept
+ {
+ if constexpr (_OtherRank == _S_rank)
+ for (size_t __i = 0; __i < _S_rank; ++__i)
+ if (!_S_is_dynamic(__i)
+ && !cmp_equal(_Extents[__i], _S_int_cast(__get_extent(__i))))
+ return false;
+ return true;
+ }
+
+ template<size_t _OtherRank, typename _GetOtherExtent>
+ constexpr void
+ _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept
+ {
+ __glibcxx_assert(_S_is_compatible_extents<_OtherRank>(__get_extent));
+ for (size_t __i = 0; __i < _S_rank_dynamic; ++__i)
+ {
+ size_t __di = __i;
+ if constexpr (_OtherRank != _S_rank_dynamic)
+ __di = _S_dynamic_index_inv(__i);
+ _M_dyn_exts[__i] = _S_int_cast(__get_extent(__di));
+ }
+ }
+
+ constexpr
+ _ExtentsStorage() noexcept = default;
+
+ template<typename _OIndexType, array _OExtents>
+ constexpr
+ _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>&
+ __other) noexcept
+ {
+ _M_init_dynamic_extents<_S_rank>([&__other](size_t __i)
+ { return __other._M_extent(__i); });
+ }
+
+ template<typename _OIndexType, size_t _Nm>
+ constexpr
+ _ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept
+ {
+ _M_init_dynamic_extents<_Nm>(
+ [&__exts](size_t __i) -> const _OIndexType&
+ { return __exts[__i]; });
+ }
+
+ static constexpr const array<size_t, _S_rank>&
+ _S_static_extents() noexcept
+ { return _Extents; }
+
+ constexpr span<const _IndexType>
+ _M_dynamic_extents(size_t __begin, size_t __end) const noexcept
+ requires (_Extents.size() > 0)
+ {
+ return {_M_dyn_exts + _S_dynamic_index(__begin),
+ _S_dynamic_index(__end) - _S_dynamic_index(__begin)};
+ }
+
+ private:
+ using _Storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type;
+ [[no_unique_address]] _Storage _M_dyn_exts{};
+ };
+
+ template<typename _OIndexType, typename _SIndexType>
+ concept __valid_index_type =
+ is_convertible_v<_OIndexType, _SIndexType> &&
+ is_nothrow_constructible_v<_SIndexType, _OIndexType>;
+
+ template<size_t _Extent, typename _IndexType>
+ concept
+ __valid_static_extent = _Extent == dynamic_extent
+ || _Extent <= __gnu_cxx::__int_traits<_IndexType>::__max;
+
+ template<typename _Extents>
+ constexpr const array<size_t, _Extents::rank()>&
+ __static_extents() noexcept
+ { return _Extents::_Storage::_S_static_extents(); }
+
+ template<typename _Extents>
+ constexpr span<const size_t>
+ __static_extents(size_t __begin, size_t __end) noexcept
+ {
+ const auto& __sta_exts = __static_extents<_Extents>();
+ return span<const size_t>(__sta_exts.data() + __begin, __end - __begin);
+ }
+
+ // Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n (exclusive)
+ template<array _Extents>
+ constexpr auto __fwd_partial_prods = [] consteval
+ {
+ constexpr size_t __rank = _Extents.size();
+ std::array<size_t, __rank> __ret;
+ size_t __prod = 1;
+ for (size_t __r = 0; __r < __rank; ++__r)
+ {
+ __ret[__r] = __prod;
+ if (size_t __ext = _Extents[__r]; __ext != dynamic_extent)
+ __prod *= __ext;
+ }
+ return __ret;
+ }();
+
+ // Pre-compute: \prod_{i = r+1}^{n-1} _Extents[i]
+ template<array _Extents>
+ constexpr auto __rev_partial_prods = [] consteval
+ {
+ constexpr size_t __rank = _Extents.size();
+ std::array<size_t, __rank> __ret;
+ size_t __prod = 1;
+ for (size_t __r = __rank; __r > 0; --__r)
+ {
+ __ret[__r - 1] = __prod;
+ if (size_t __ext = _Extents[__r - 1]; __ext != dynamic_extent)
+ __prod *= __ext;
+ }
+ return __ret;
+ }();
+
+ template<typename _Extents>
+ constexpr span<const typename _Extents::index_type>
+ __dynamic_extents(const _Extents& __exts, size_t __begin = 0,
+ size_t __end = _Extents::rank()) noexcept
+ { return __exts._M_exts._M_dynamic_extents(__begin, __end); }
+ }
+
+#if __glibcxx_submdspan
+ struct full_extent_t
+ {
+ explicit full_extent_t() = default;
+ };
+
+ inline constexpr full_extent_t full_extent{};
+
+ template<typename _OffsetType, typename _ExtentType, typename _StrideType>
+ struct strided_slice
+ {
+ static_assert(__is_signed_or_unsigned_integer<_OffsetType>::value
+ || __detail::__integral_constant_like<_OffsetType>);
+ static_assert(__is_signed_or_unsigned_integer<_ExtentType>::value
+ || __detail::__integral_constant_like<_ExtentType>);
+ static_assert(__is_signed_or_unsigned_integer<_StrideType>::value
+ || __detail::__integral_constant_like<_StrideType>);
+
+ using offset_type = _OffsetType;
+ using extent_type = _ExtentType;
+ using stride_type = _StrideType;
+
+ [[no_unique_address]] offset_type offset{};
+ [[no_unique_address]] extent_type extent{};
+ [[no_unique_address]] stride_type stride{};
+ };
+
+ template<typename _Mapping>
+ struct submdspan_mapping_result
+ {
+ [[no_unique_address]] _Mapping mapping = _Mapping();
+ size_t offset{};
+ };
+
+ template<typename _Tp>
+ constexpr bool __is_submdspan_mapping_result = false;
+
+ template<typename _Mapping>
+ constexpr bool __is_submdspan_mapping_result<submdspan_mapping_result<_Mapping>> = true;
+
+ template<typename _Mapping>
+ concept __submdspan_mapping_result = __is_submdspan_mapping_result<_Mapping>;
+
+#endif // __glibcxx_submdspan
+
+ template<typename _IndexType, size_t... _Extents>
+ class extents
+ {
+ static_assert(__is_signed_or_unsigned_integer<_IndexType>::value,
+ "IndexType must be a signed or unsigned integer type");
+ static_assert(
+ (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...),
+ "Extents must either be dynamic or representable as IndexType");
+
+ using _Storage = __mdspan::_ExtentsStorage<
+ _IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>;
+ [[no_unique_address]] _Storage _M_exts;
+
+ public:
+ using index_type = _IndexType;
+ using size_type = make_unsigned_t<index_type>;
+ using rank_type = size_t;
+
+ static constexpr rank_type
+ rank() noexcept { return _Storage::_S_rank; }
+
+ static constexpr rank_type
+ rank_dynamic() noexcept { return _Storage::_S_rank_dynamic; }
+
+ static constexpr size_t
+ static_extent(rank_type __r) noexcept
+ {
+ __glibcxx_assert(__r < rank());
+ if constexpr (rank() == 0)
+ __builtin_trap();
+ else
+ return _Storage::_S_static_extent(__r);
+ }
+
+ constexpr index_type
+ extent(rank_type __r) const noexcept
+ {
+ __glibcxx_assert(__r < rank());
+ if constexpr (rank() == 0)
+ __builtin_trap();
+ else
+ return _M_exts._M_extent(__r);
+ }
+
+ constexpr
+ extents() noexcept = default;
+
+ private:
+ static consteval bool
+ _S_is_less_dynamic(size_t __ext, size_t __oext)
+ { return (__ext != dynamic_extent) && (__oext == dynamic_extent); }
+
+ template<typename _OIndexType, size_t... _OExtents>
+ static consteval bool
+ _S_ctor_explicit()
+ {
+ return (_S_is_less_dynamic(_Extents, _OExtents) || ...)
+ || (__gnu_cxx::__int_traits<index_type>::__max
+ < __gnu_cxx::__int_traits<_OIndexType>::__max);
+ }
+
+ template<size_t... _OExtents>
+ static consteval bool
+ _S_is_compatible_extents()
+ {
+ if constexpr (sizeof...(_OExtents) != rank())
+ return false;
+ else
+ return ((_OExtents == dynamic_extent || _Extents == dynamic_extent
+ || _OExtents == _Extents) && ...);
+ }
+
+ public:
+ template<typename _OIndexType, size_t... _OExtents>
+ requires (_S_is_compatible_extents<_OExtents...>())
+ constexpr explicit(_S_ctor_explicit<_OIndexType, _OExtents...>())
+ extents(const extents<_OIndexType, _OExtents...>& __other) noexcept
+ : _M_exts(__other._M_exts)
+ { }
+
+ template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
+ requires (sizeof...(_OIndexTypes) == rank()
+ || sizeof...(_OIndexTypes) == rank_dynamic())
+ constexpr explicit extents(_OIndexTypes... __exts) noexcept
+ : _M_exts(span<const _IndexType, sizeof...(_OIndexTypes)>(
+ initializer_list{static_cast<_IndexType>(std::move(__exts))...}))
+ { }
+
+ template<typename _OIndexType, size_t _Nm>
+ requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
+ && (_Nm == rank() || _Nm == rank_dynamic())
+ constexpr explicit(_Nm != rank_dynamic())
+ extents(span<_OIndexType, _Nm> __exts) noexcept
+ : _M_exts(span<const _OIndexType, _Nm>(__exts))
+ { }
+
+ template<typename _OIndexType, size_t _Nm>
+ requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
+ && (_Nm == rank() || _Nm == rank_dynamic())
+ constexpr explicit(_Nm != rank_dynamic())
+ extents(const array<_OIndexType, _Nm>& __exts) noexcept
+ : _M_exts(span<const _OIndexType, _Nm>(__exts))
+ { }
+
+ template<typename _OIndexType, size_t... _OExtents>
+ friend constexpr bool
+ operator==(const extents& __self,
+ const extents<_OIndexType, _OExtents...>& __other) noexcept
+ {
+ if constexpr (!_S_is_compatible_extents<_OExtents...>())
+ return false;
+ else
+ {
+ auto __impl = [&__self, &__other]<size_t... _Counts>(
+ index_sequence<_Counts...>)
+ { return (cmp_equal(__self.extent(_Counts),
+ __other.extent(_Counts)) && ...); };
+ return __impl(make_index_sequence<__self.rank()>());
+ }
+ }
+
+ private:
+ friend constexpr const array<size_t, rank()>&
+ __mdspan::__static_extents<extents>() noexcept;
+
+ friend constexpr span<const index_type>
+ __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t)
+ noexcept;
+
+ template<typename _OIndexType, size_t... _OExtents>
+ friend class extents;
+ };
+
+ namespace __mdspan
+ {
+ template<typename _Tp, size_t _Nm>
+ constexpr bool
+ __contains_zero(span<_Tp, _Nm> __exts) noexcept
+ {
+ for (size_t __i = 0; __i < __exts.size(); ++__i)
+ if (__exts[__i] == 0)
+ return true;
+ return false;
+ }
+
+ template<typename _Tp, size_t _Nm>
+ consteval bool
+ __contains_zero(const array<_Tp, _Nm>& __exts) noexcept
+ { return __contains_zero(span<const _Tp>(__exts)); }
+
+ template<typename _Extents>
+ constexpr bool
+ __empty(const _Extents& __exts) noexcept
+ {
+ if constexpr (__contains_zero(__static_extents<_Extents>()))
+ return true;
+ else if constexpr (_Extents::rank_dynamic() > 0)
+ return __contains_zero(__dynamic_extents(__exts));
+ else
+ return false;
+ }
+
+ template<typename _Extents>
+ constexpr typename _Extents::index_type
+ __extents_prod(const _Extents& __exts, size_t __sta_prod, size_t __begin,
+ size_t __end) noexcept
+ {
+ if (__sta_prod == 0)
+ return 0;
+
+ size_t __ret = __sta_prod;
+ if constexpr (_Extents::rank_dynamic() > 0)
+ for (auto __factor : __dynamic_extents(__exts, __begin, __end))
+ __ret *= size_t(__factor);
+ return static_cast<typename _Extents::index_type>(__ret);
+ }
+
+ // Preconditions: _r < _Extents::rank()
+ template<typename _Extents>
+ constexpr typename _Extents::index_type
+ __fwd_prod(const _Extents& __exts, size_t __begin, size_t __end) noexcept
+ {
+ size_t __sta_prod = [__begin, __end] {
+ span<const size_t> __sta_exts
+ = __static_extents<_Extents>(__begin, __end);
+ size_t __ret = 1;
+ for(auto __ext : __sta_exts)
+ if (__ext != dynamic_extent)
+ __ret *= __ext;
+ return __ret;
+ }();
+ return __extents_prod(__exts, __sta_prod, __begin, __end);
+ }
+
+ template<typename _Extents>
+ constexpr typename _Extents::index_type
+ __fwd_prod(const _Extents& __exts, size_t __r) noexcept
+ {
+ constexpr size_t __rank = _Extents::rank();
+ constexpr auto& __sta_exts = __static_extents<_Extents>();
+ if constexpr (__rank == 1)
+ return 1;
+ else if constexpr (__rank == 2)
+ return __r == 0 ? 1 : __exts.extent(0);
+ else if constexpr (__all_dynamic(std::span(__sta_exts).first(__rank-1)))
+ return __extents_prod(__exts, 1, 0, __r);
+ else
+ {
+ size_t __sta_prod = __fwd_partial_prods<__sta_exts>[__r];
+ return __extents_prod(__exts, __sta_prod, 0, __r);
+ }
+ }
+
+ template<typename _IndexType, size_t _Nm>
+ consteval _IndexType
+ __fwd_prod(span<const _IndexType, _Nm> __values)
+ {
+ _IndexType __ret = 1;
+ for(auto __value : __values)
+ __ret *= __value;
+ return __ret;
+ }
+
+ // Preconditions: _r < _Extents::rank()
+ template<typename _Extents>
+ constexpr typename _Extents::index_type
+ __rev_prod(const _Extents& __exts, size_t __r) noexcept
+ {
+ constexpr size_t __rank = _Extents::rank();
+ constexpr auto& __sta_exts = __static_extents<_Extents>();
+ if constexpr (__rank == 1)
+ return 1;
+ else if constexpr (__rank == 2)
+ return __r == 0 ? __exts.extent(1) : 1;
+ else if constexpr (__all_dynamic(std::span(__sta_exts).last(__rank-1)))
+ return __extents_prod(__exts, 1, __r + 1, __rank);
+ else
+ {
+ size_t __sta_prod = __rev_partial_prods<__sta_exts>[__r];
+ return __extents_prod(__exts, __sta_prod, __r + 1, __rank);
+ }
+ }
+
+ template<typename _Extents>
+ constexpr typename _Extents::index_type
+ __size(const _Extents& __exts) noexcept
+ {
+ constexpr size_t __sta_prod = [] {
+ span<const size_t> __sta_exts = __static_extents<_Extents>();
+ size_t __ret = 1;
+ for(auto __ext : __sta_exts)
+ if (__ext != dynamic_extent)
+ __ret *= __ext;
+ return __ret;
+ }();
+ return __extents_prod(__exts, __sta_prod, 0, _Extents::rank());
+ }
+
+ template<typename _IndexType, size_t... _Counts>
+ auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
+ -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
+ }
+
+ template<typename _IndexType, size_t _Rank>
+ using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>(
+ make_index_sequence<_Rank>()));
+
+#if __glibcxx_mdspan >= 202406L
+ template<size_t _Rank, typename _IndexType = size_t>
+ using dims = dextents<_IndexType, _Rank>;
+#endif
+
+ template<typename... _Integrals>
+ requires (is_convertible_v<_Integrals, size_t> && ...)
+ explicit extents(_Integrals...) ->
+ extents<size_t, __detail::__maybe_static_ext<_Integrals>...>;
+
+ struct layout_left
+ {
+ template<typename _Extents>
+ class mapping;
+ };
+
+ struct layout_right
+ {
+ template<typename _Extents>
+ class mapping;
+ };
+
+ struct layout_stride
+ {
+ template<typename _Extents>
+ class mapping;
+ };
+
+#ifdef __glibcxx_padded_layouts
+ template<size_t _PaddingValue>
+ struct layout_left_padded
+ {
+ template<typename _Extents>
+ class mapping;
+ };
+
+ template<size_t _PaddingValue>
+ struct layout_right_padded
+ {
+ template<typename _Extents>
+ class mapping;
+ };
+#endif
+
+ namespace __mdspan
+ {
+ template<typename _Tp>
+ constexpr bool __is_extents = false;
+
+ template<typename _IndexType, size_t... _Extents>
+ constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true;
+
+ template<typename _Extents, typename... _Indices>
+ constexpr typename _Extents::index_type
+ __linear_index_left(const _Extents& __exts, _Indices... __indices)
+ noexcept
+ {
+ using _IndexType = typename _Extents::index_type;
+ _IndexType __res = 0;
+ if constexpr (sizeof...(__indices) > 0)
+ {
+ _IndexType __mult = 1;
+ auto __update = [&, __pos = 0u](_IndexType __idx) mutable
+ {
+ _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __exts.extent(__pos)));
+ __res += __idx * __mult;
+ __mult *= __exts.extent(__pos);
+ ++__pos;
+ };
+ (__update(__indices), ...);
+ }
+ return __res;
+ }
+
+ template<typename _IndexType>
+ consteval _IndexType
+ __static_quotient(std::span<const size_t> __sta_exts,
+ _IndexType __nom = __gnu_cxx::__int_traits<_IndexType>::__max)
+ {
+ for (auto __factor : __sta_exts)
+ {
+ if (__factor != dynamic_extent)
+ __nom /= _IndexType(__factor);
+ if (__nom == 0)
+ break;
+ }
+ return __nom;
+ }
+
+ template<typename _Extents,
+ typename _IndexType = typename _Extents::index_type>
+ requires __is_extents<_Extents>
+ consteval _IndexType
+ __static_quotient(_IndexType __nom
+ = __gnu_cxx::__int_traits<_IndexType>::__max)
+ {
+ std::span<const size_t> __sta_exts = __static_extents<_Extents>();
+ return __static_quotient<_IndexType>(__sta_exts, __nom);
+ }
+
+ template<typename _Extents>
+ constexpr bool
+ __is_representable_extents(const _Extents& __exts) noexcept
+ {
+ using _IndexType = _Extents::index_type;
+
+ if constexpr (__contains_zero(__static_extents<_Extents>()))
+ return true;
+ else
+ {
+ constexpr auto __sta_quo = __static_quotient<_Extents>();
+ if constexpr (_Extents::rank_dynamic() == 0)
+ return __sta_quo != 0;
+ else
+ {
+ auto __dyn_exts = __dynamic_extents(__exts);
+ if (__contains_zero(__dyn_exts))
+ return true;
+
+ if constexpr (__sta_quo == 0)
+ return false;
+ else
+ {
+ auto __dyn_quo = _IndexType(__sta_quo);
+ for (auto __factor : __dyn_exts)
+ {
+ __dyn_quo /= __factor;
+ if (__dyn_quo == 0)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ }
+
+ template<typename _Extents, typename _IndexType>
+ concept __representable_size = _Extents::rank_dynamic() != 0
+ || __contains_zero(__static_extents<_Extents>())
+ || (__static_quotient<_Extents, _IndexType>() != 0);
+
+ template<typename _Layout, typename _Mapping>
+ concept __mapping_of =
+ is_same_v<typename _Layout::template mapping<
+ typename _Mapping::extents_type>,
+ _Mapping>;
+
+ template<template<size_t> typename _Layout, typename _Mapping>
+ concept __padded_mapping_of = __mapping_of<
+ _Layout<_Mapping::padding_value>, _Mapping>;
+
+#ifdef __glibcxx_padded_layouts
+ template<typename _Mapping>
+ constexpr bool __is_left_padded_mapping = __padded_mapping_of<
+ layout_left_padded, _Mapping>;
+
+ template<typename _Mapping>
+ constexpr bool __is_right_padded_mapping = __padded_mapping_of<
+ layout_right_padded, _Mapping>;
+
+ template<typename _Mapping>
+ constexpr bool __is_padded_mapping = __is_left_padded_mapping<_Mapping>
+ || __is_right_padded_mapping<_Mapping>;
+#endif
+
+ template<typename _PaddedMapping>
+ consteval size_t
+ __get_static_stride()
+ { return _PaddedMapping::_PaddedStorage::_S_static_stride; }
+
+ template<typename _Mapping>
+ concept __standardized_mapping = __mapping_of<layout_left, _Mapping>
+ || __mapping_of<layout_right, _Mapping>
+ || __mapping_of<layout_stride, _Mapping>
+#ifdef __glibcxx_padded_layouts
+ || __is_left_padded_mapping<_Mapping>
+ || __is_right_padded_mapping<_Mapping>
+#endif
+ ;
+
+ // A tag type to create internal ctors.
+ class __internal_ctor
+ { };
+
+ template<typename _Mapping>
+ constexpr typename _Mapping::index_type
+ __offset(const _Mapping& __m) noexcept
+ {
+ using _IndexType = typename _Mapping::index_type;
+ constexpr auto __rank = _Mapping::extents_type::rank();
+
+ if constexpr (__standardized_mapping<_Mapping>)
+ return 0;
+ else if (__empty(__m.extents()))
+ return 0;
+ else
+ {
+ auto __impl = [&__m]<size_t... _Counts>(index_sequence<_Counts...>)
+ { return __m(((void) _Counts, _IndexType(0))...); };
+ return __impl(make_index_sequence<__rank>());
+ }
+ }
+
+#ifdef __glibcxx_submdspan
+ template<typename _Tp>
+ constexpr bool __is_strided_slice = false;
+
+ template<typename _OffsetType, typename _ExtentType, typename _StrideType>
+ constexpr bool __is_strided_slice<strided_slice<_OffsetType,
+ _ExtentType, _StrideType>> = true;
+
+ template<typename _IndexType, typename _OIndexType>
+ consteval bool
+ __is_representable_integer(_OIndexType __value)
+ {
+ constexpr auto __min = __gnu_cxx::__int_traits<_IndexType>::__min;
+ constexpr auto __max = __gnu_cxx::__int_traits<_IndexType>::__max;
+ return std::cmp_less_equal(__min, __value)
+ && std::cmp_less_equal(__value, __max);
+ }
+
+ template<typename _Tp>
+ constexpr bool __is_constant_wrapper = false;
+
+ template<_CwFixedValue _Xv, typename _Tp>
+ constexpr bool __is_constant_wrapper<constant_wrapper<_Xv, _Tp>>
+ = true;
+
+ template<size_t _Index, typename _Extents>
+ constexpr auto
+ __extract_extent(const _Extents& __exts)
+ {
+ using _IndexType = typename _Extents::index_type;
+ return extents<_IndexType, _Extents::static_extent(_Index)>{
+ __exts.extent(_Index)};
+ }
+
+ template<typename _Slice, typename _IndexType>
+ concept __acceptable_slice_type = same_as<_Slice, full_extent_t>
+ || same_as<_Slice, _IndexType> || __is_constant_wrapper<_Slice>
+ || __is_strided_slice<_Slice>;
+
+ template<typename _IndexType, typename... _Slices>
+ consteval auto
+ __subrank()
+ {
+ return (static_cast<size_t>(!convertible_to<_Slices, _IndexType>)
+ + ... + 0);
+ }
+
+ template<typename _IndexType, typename... _Slices>
+ consteval auto
+ __inv_map_rank()
+ {
+ constexpr auto __rank = sizeof...(_Slices);
+ constexpr auto __sub_rank = __subrank<_IndexType, _Slices...>();
+ auto __map = std::array<size_t, __sub_rank>{};
+ auto __is_int_like = std::array<bool, __rank>{
+ convertible_to<_Slices, _IndexType>...};
+
+ size_t __i = 0;
+ for (size_t __k = 0; __k < __rank; ++__k)
+ if (!__is_int_like[__k])
+ __map[__i++] = __k;
+ return __map;
+ }
+
+ template<typename _Slice>
+ constexpr auto
+ __slice_begin(_Slice __slice)
+ {
+ if constexpr (same_as<_Slice, full_extent_t>)
+ return 0;
+ else if constexpr (__is_strided_slice<_Slice>)
+ return __slice.offset;
+ else
+ return __slice; // collapsing slice
+ }
+
+ template<typename _Mapping, typename... _Slices>
+ constexpr size_t
+ __suboffset(const _Mapping& __mapping, const _Slices&... __slices)
+ {
+ using _IndexType = typename _Mapping::index_type;
+ auto __any_past_the_end = [&]<size_t... _Is>(index_sequence<_Is...>)
+ {
+ auto __is_past_the_end = [](const auto& __slice, const auto& __ext)
+ {
+ using _Slice = remove_cvref_t<decltype(__slice)>;
+ if constexpr (is_convertible_v<_Slice, _IndexType>)
+ return false;
+ else if constexpr (same_as<_Slice, full_extent_t>
+ && __ext.static_extent(0) != 0
+ && __ext.static_extent(0) != dynamic_extent)
+ return false;
+ else
+ return __mdspan::__slice_begin(__slice) == __ext.extent(0);
+ };
+
+ const auto& __exts = __mapping.extents();
+ return ((__is_past_the_end(__slices...[_Is],
+ __mdspan::__extract_extent<_Is>(__exts))) || ...);
+ };
+
+ if constexpr ((same_as<_Slices, full_extent_t> && ...))
+ return __mdspan::__offset(__mapping);
+
+ if (__any_past_the_end(std::make_index_sequence<sizeof...(__slices)>()))
+ return __mapping.required_span_size();
+ return __mapping(__mdspan::__slice_begin(__slices)...);
+ }
+
+ template<typename _IndexType, size_t _Extent, typename _Slice>
+ consteval size_t
+ __static_slice_extent()
+ {
+ if constexpr (same_as<_Slice, full_extent_t>)
+ return _Extent;
+ else if constexpr (same_as<_Slice, constant_wrapper<_IndexType(0)>>)
+ return 0;
+ else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>
+ && __is_constant_wrapper<typename _Slice::stride_type>)
+ return 1 + ((typename _Slice::extent_type{}) - 1)
+ / (typename _Slice::stride_type{});
+ else
+ return dynamic_extent;
+ }
+
+ template<size_t _K, typename _Extents, typename _Slice>
+ constexpr typename _Extents::index_type
+ __dynamic_slice_extent(const _Extents& __exts, _Slice __slice)
+ {
+ if constexpr (__is_strided_slice<_Slice>)
+ return __slice.extent == 0 ? 0 : 1 + (__slice.extent - 1) / __slice.stride;
+ else
+ return __exts.extent(_K);
+ }
+
+ template<typename _IndexType, size_t... _Extents, typename... _Slices>
+ requires (sizeof...(_Slices) == sizeof...(_Extents))
+ constexpr auto
+ __subextents(const extents<_IndexType, _Extents...>& __exts,
+ _Slices... __slices)
+ {
+ constexpr auto __inv_map = __mdspan::__inv_map_rank<_IndexType, _Slices...>();
+ auto __impl = [&]<size_t... _Indices>(std::index_sequence<_Indices...>)
+ {
+ using _SubExts = extents<_IndexType,
+ __mdspan::__static_slice_extent<_IndexType,
+ _Extents...[__inv_map[_Indices]],
+ _Slices...[__inv_map[_Indices]]>()...>;
+ if constexpr (_SubExts::rank_dynamic() == 0)
+ return _SubExts{};
+ else
+ {
+ using _StaticSubExtents = __mdspan::_StaticExtents<
+ __mdspan::__static_extents<_SubExts>()>;
+ auto __create = [&]<size_t... _Is>(std::index_sequence<_Is...>)
+ {
+ constexpr auto __slice_idx = [__inv_map](size_t __i) consteval
+ {
+ return __inv_map[_StaticSubExtents::_S_dynamic_index_inv(__i)];
+ };
+
+ return _SubExts{__mdspan::__dynamic_slice_extent<__slice_idx(_Is)>(
+ __exts, __slices...[__slice_idx(_Is)])...};
+ };
+ constexpr auto __dyn_subrank = _SubExts::rank_dynamic();
+ return __create(std::make_index_sequence<__dyn_subrank>());
+ }
+ };
+
+ return __impl(std::make_index_sequence<__inv_map.size()>());
+ }
+
+ enum class _LayoutSide
+ {
+ __left,
+ __right,
+ __unknown
+ };
+
+ template<typename _Mapping>
+ consteval _LayoutSide
+ __mapping_side()
+ {
+ if constexpr (__is_left_padded_mapping<_Mapping>
+ || __mapping_of<layout_left, _Mapping>)
+ return _LayoutSide::__left;
+ if constexpr (__is_right_padded_mapping<_Mapping>
+ || __mapping_of<layout_right, _Mapping>)
+ return _LayoutSide::__right;
+ else
+ return _LayoutSide::__unknown;
+ }
+
+ template<_LayoutSide _Side, size_t _Rank>
+ struct _StridesTrait
+ {
+ static constexpr const _LayoutSide _S_side = _Side;
+
+ static constexpr size_t
+ _S_idx(size_t __k) noexcept
+ {
+ if constexpr (_Side == _LayoutSide::__left)
+ return __k;
+ else
+ return _Rank - 1 - __k;
+ }
+
+ // Unifies the formulas for computing strides for padded and unpadded
+ // layouts.
+ template<typename _Mapping>
+ static constexpr typename _Mapping::index_type
+ _S_padded_extent(const _Mapping& __mapping, size_t __k)
+ {
+ if (__k == 0)
+ return __mapping.stride(_S_idx(1));
+ else
+ return __mapping.extents().extent(_S_idx(__k));
+ }
+
+ template<typename _IndexType, typename... _Slices>
+ static consteval auto
+ _S_inv_map()
+ {
+ static_assert(_Side != _LayoutSide::__unknown);
+ auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>)
+ {
+ return __mdspan::__inv_map_rank<_IndexType, _Slices...[_S_idx(_Is)]...>();
+ };
+ return __impl(std::make_index_sequence<_Rank>());
+ }
+ };
+
+ template<typename _SubExts, typename _Mapping, typename... _Slices>
+ constexpr auto
+ __substrides_generic(const _Mapping& __mapping, const _Slices&... __slices)
+ {
+ using _IndexType = typename _Mapping::index_type;
+ if constexpr (_SubExts::rank() == 0)
+ return array<_IndexType, _SubExts::rank()>{};
+ else
+ {
+ auto __stride = [&__mapping](size_t __k, auto __slice) -> _IndexType
+ {
+ if constexpr (__is_strided_slice<decltype(__slice)>)
+ if (__slice.stride < __slice.extent)
+ return __mapping.stride(__k) * __slice.stride;
+ return __mapping.stride(__k);
+ };
+
+ auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>)
+ {
+ constexpr auto __inv_map
+ = __mdspan::__inv_map_rank<_IndexType, _Slices...>();
+ return array<_IndexType, _SubExts::rank()>{
+ __stride(__inv_map[_Is], __slices...[__inv_map[_Is]])...};
+ };
+ return __impl(std::make_index_sequence<_SubExts::rank()>());
+ }
+ };
+
+ template<typename _SubExts, typename _Mapping, typename... _Slices>
+ constexpr auto
+ __substrides_standardized(const _Mapping& __mapping,
+ const _Slices&... __slices)
+ {
+ using _IndexType = typename _Mapping::index_type;
+ using _Trait = _StridesTrait<__mapping_side<_Mapping>(),
+ _Mapping::extents_type::rank()>;
+ using _SubTrait = _StridesTrait<__mapping_side<_Mapping>(), _SubExts::rank()>;
+
+ constexpr size_t __sub_rank = _SubExts::rank();
+
+ std::array<_IndexType, __sub_rank> __ret;
+ if constexpr (__sub_rank > 0)
+ {
+ constexpr auto __inv_map
+ = _Trait::template _S_inv_map<_IndexType, _Slices...>();
+ auto __loop = [&]<size_t... _Ks>(std::index_sequence<_Ks...>)
+ {
+ size_t __i0 = 0;
+ size_t __stride = 1;
+ auto __body = [&](size_t __k, auto __slice)
+ {
+ for (size_t __i = __i0; __i < __inv_map[__k]; ++__i)
+ __stride *= _Trait::_S_padded_extent(__mapping, __i);
+
+ size_t __krev = _SubTrait::_S_idx(__k);
+ if constexpr (__is_strided_slice<decltype(__slice)>)
+ {
+ if (__slice.stride < __slice.extent)
+ __ret[__krev] = __stride * __slice.stride;
+ else
+ __ret[__krev] = __stride;
+ }
+ else
+ __ret[__krev] = __stride;
+
+ __i0 = __inv_map[__k];
+ };
+
+ ((__body(_Ks, __slices...[_Trait::_S_idx(__inv_map[_Ks])])),...);
+ };
+ __loop(std::make_index_sequence<__sub_rank>());
+ }
+ return __ret;
+ }
+
+
+ template<typename _SubExts, typename _Mapping, typename... _Slices>
+ constexpr auto
+ __substrides(const _Mapping& __mapping, const _Slices&... __slices)
+ {
+ if constexpr (__mdspan::__mapping_side<_Mapping>() == _LayoutSide::__unknown)
+ return __mdspan::__substrides_generic<_SubExts>(__mapping, __slices...);
+ else
+ return __mdspan::__substrides_standardized<_SubExts>(__mapping, __slices...);
+ }
+
+ template<typename _Slice>
+ concept __is_unit_stride_slice = (__mdspan::__is_strided_slice<_Slice>
+ && __mdspan::__is_constant_wrapper<typename _Slice::stride_type>
+ && _Slice::stride_type::value == 1)
+ || std::same_as<_Slice, full_extent_t>;
+
+ // These are (forced) exclusive categories:
+ // - full & collapsing: obvious,
+ // - unit_strided_slice: strided_slice{a, b, cw<1>}, but not `full`,
+ // - strided_slice: strided_slice{a, b, c} with c != cw<1>.
+ enum class _SliceKind
+ {
+ __strided_slice,
+ __unit_strided_slice,
+ __full,
+ __collapsing
+ };
+
+ template<typename _Slice>
+ consteval _SliceKind
+ __make_slice_kind()
+ {
+ if constexpr (std::same_as<_Slice, full_extent_t>)
+ return _SliceKind::__full;
+ else if constexpr (__mdspan::__is_strided_slice<_Slice>)
+ {
+ if constexpr (__mdspan::__is_unit_stride_slice<_Slice>)
+ return _SliceKind::__unit_strided_slice;
+ else
+ return _SliceKind::__strided_slice;
+ }
+ else
+ return _SliceKind::__collapsing;
+ }
+
+ template<typename... _Slices>
+ consteval array<_SliceKind, sizeof...(_Slices)>
+ __make_slice_kind_array()
+ {
+ return array<_SliceKind, sizeof...(_Slices)>{
+ __mdspan::__make_slice_kind<_Slices>()...};
+ }
+
+ // __block_size - 1
+ // [full, ..., full, unit_slice , *]
+ consteval bool
+ __is_block(span<const _SliceKind> __slice_kinds, size_t __block_size)
+ {
+ if (__block_size == 0)
+ return false;
+
+ if (__block_size > __slice_kinds.size())
+ return false;
+
+ for (size_t __i = 0; __i < __block_size - 1; ++__i)
+ if (__slice_kinds[__i] != _SliceKind::__full)
+ return false;
+
+ auto __last = __slice_kinds[__block_size - 1];
+ return __last == _SliceKind::__full
+ || __last == _SliceKind::__unit_strided_slice;
+ }
+
+ // __u __u + __sub_rank-2
+ // [unit_slice, i, ..., k, full, ..., full, unit_slice, *]
+ static consteval size_t
+ __padded_block_begin_generic(span<const _SliceKind> __slice_kinds,
+ size_t __sub_rank)
+ {
+ if (__slice_kinds[0] != _SliceKind::__full
+ && __slice_kinds[0] != _SliceKind::__unit_strided_slice)
+ return dynamic_extent;
+ else if (__slice_kinds.size() == 1)
+ return dynamic_extent;
+ else
+ {
+ size_t __u = 1;
+ while(__u < __slice_kinds.size()
+ && __slice_kinds[__u] == _SliceKind::__collapsing)
+ ++__u;
+
+ if (__mdspan::__is_block(__slice_kinds.subspan(__u), __sub_rank -1))
+ return __u;
+ return dynamic_extent;
+ }
+ }
+
+ template<_LayoutSide _Side, size_t _Nm>
+ static consteval size_t
+ __padded_block_begin(span<const _SliceKind, _Nm> __slice_kinds, size_t __sub_rank)
+ {
+ if constexpr (_Side == _LayoutSide::__left)
+ return __mdspan::__padded_block_begin_generic(__slice_kinds, __sub_rank);
+ else
+ {
+ std::array<_SliceKind, _Nm> __rev_slices;
+ for(size_t __i = 0; __i < _Nm; ++__i)
+ __rev_slices[__i] = __slice_kinds[_Nm - 1 - __i];
+ auto __rev_slice_kinds = span<const _SliceKind>(__rev_slices);
+
+ auto __u = __mdspan::__padded_block_begin_generic(__rev_slice_kinds,
+ __sub_rank);
+ return __u == dynamic_extent ? dynamic_extent : _Nm - 1 - __u;
+ }
+ }
+
+ template<_LayoutSide _Side, bool _Padded>
+ struct _SubMdspanMapping;
+
+ template<>
+ struct _SubMdspanMapping<_LayoutSide::__left, false>
+ {
+ using _Layout = layout_left;
+ template<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>;
+
+ template<typename _Mapping, size_t _Us>
+ static consteval size_t
+ _S_pad()
+ {
+ using _Extents = typename _Mapping::extents_type;
+ constexpr auto __sta_exts = __mdspan::__static_extents<_Extents>(0, _Us);
+ if constexpr (!__mdspan::__all_static(__sta_exts))
+ return dynamic_extent;
+ else
+ return __mdspan::__fwd_prod(__sta_exts);
+ }
+
+ template<size_t _Nm>
+ static consteval bool
+ _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, size_t __sub_rank)
+ { return __mdspan::__is_block(__slice_kinds, __sub_rank); }
+ };
+
+ template<>
+ struct _SubMdspanMapping<_LayoutSide::__left, true>
+ {
+ using _Layout = layout_left;
+ template<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>;
+
+ template<typename _Mapping, size_t _Us>
+ static consteval size_t
+ _S_pad()
+ {
+ using _Extents = typename _Mapping::extents_type;
+ constexpr auto __sta_exts
+ = __mdspan::__static_extents<_Extents>(1, _Us);
+ constexpr auto __sta_padstride
+ = __mdspan::__get_static_stride<_Mapping>();
+ if constexpr (__sta_padstride == dynamic_extent
+ || !__mdspan::__all_static(__sta_exts))
+ return dynamic_extent;
+ else
+ return __sta_padstride * __mdspan::__fwd_prod(__sta_exts);
+ }
+
+ template<size_t _Nm>
+ static consteval bool
+ _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds,
+ size_t __sub_rank)
+ {
+ if (__sub_rank == 1)
+ return __slice_kinds[0] == _SliceKind::__unit_strided_slice
+ || __slice_kinds[0] == _SliceKind::__full;
+ else
+ return false;
+ }
+ };
+
+ template<>
+ struct _SubMdspanMapping<_LayoutSide::__right, false>
+ {
+ using _Layout = layout_right;
+ template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>;
+
+ template<typename _Mapping, size_t _Us>
+ static consteval size_t
+ _S_pad()
+ {
+ using _Extents = typename _Mapping::extents_type;
+ constexpr auto __rank = _Extents::rank();
+ constexpr auto __sta_exts
+ = __mdspan::__static_extents<_Extents>(_Us + 1, __rank);
+ if constexpr (!__mdspan::__all_static(__sta_exts))
+ return dynamic_extent;
+ else
+ return __fwd_prod(__sta_exts);
+ }
+
+ template<size_t _Nm>
+ static consteval bool
+ _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds,
+ size_t __sub_rank)
+ {
+ auto __rev_slice_kinds = array<_SliceKind, _Nm>{};
+ for(size_t __i = 0; __i < _Nm; ++__i)
+ __rev_slice_kinds[__i] = __slice_kinds[_Nm - 1 - __i];
+ return __mdspan::__is_block(span(__rev_slice_kinds), __sub_rank);
+ }
+ };
+
+ template<>
+ struct _SubMdspanMapping<_LayoutSide::__right, true>
+ {
+ using _Layout = layout_right;
+ template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>;
+
+ template<typename _Mapping, size_t _Us>
+ static consteval size_t
+ _S_pad()
+ {
+ using _Extents = typename _Mapping::extents_type;
+ constexpr auto __rank = _Extents::rank();
+ constexpr auto __sta_exts
+ = __mdspan::__static_extents<_Extents>(_Us + 1, __rank - 1);
+ constexpr auto __sta_padstride
+ = __mdspan::__get_static_stride<_Mapping>();
+ if constexpr (__sta_padstride == dynamic_extent
+ || !__mdspan::__all_static(__sta_exts))
+ return dynamic_extent;
+ else
+ return __sta_padstride * __mdspan::__fwd_prod(__sta_exts);
+ }
+
+ template<size_t _Nm>
+ static consteval bool
+ _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds,
+ size_t __sub_rank)
+ {
+ if (__sub_rank == 1)
+ return __slice_kinds[_Nm - 1] == _SliceKind::__unit_strided_slice
+ || __slice_kinds[_Nm - 1] == _SliceKind::__full;
+ else
+ return false;
+ }
+ };
+
+
+ template<typename _Mapping>
+ constexpr auto
+ __submdspan_mapping_impl(const _Mapping& __mapping)
+ { return submdspan_mapping_result{__mapping, 0}; }
+
+ template<typename _Mapping, typename... _Slices>
+ requires (sizeof...(_Slices) > 0)
+ constexpr auto
+ __submdspan_mapping_impl(const _Mapping& __mapping, _Slices... __slices)
+ {
+ using _IndexType = typename _Mapping::index_type;
+ static_assert((__acceptable_slice_type<_Slices, _IndexType> && ...));
+
+ constexpr auto __side = __mdspan::__mapping_side<_Mapping>();
+ constexpr auto __rank = sizeof...(_Slices);
+ using _Trait = _SubMdspanMapping<__side, __is_padded_mapping<_Mapping>>;
+ using _SliceView = span<const _SliceKind, __rank>;
+
+ constexpr auto __slice_kinds = __mdspan::__make_slice_kind_array<_Slices...>();
+ auto __offset = __mdspan::__suboffset(__mapping, __slices...);
+ auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...);
+ using _SubExts = decltype(__sub_exts);
+ constexpr auto __sub_rank = _SubExts::rank();
+ if constexpr (__sub_rank == 0)
+ return submdspan_mapping_result{
+ typename _Trait::_Layout::mapping(__sub_exts), __offset};
+ else if constexpr (_Trait::_S_is_unpadded_submdspan(
+ _SliceView(__slice_kinds), __sub_rank))
+ return submdspan_mapping_result{
+ typename _Trait::_Layout::mapping(__sub_exts), __offset};
+ else if constexpr (
+ constexpr auto __u = __padded_block_begin<__side>(
+ _SliceView(__slice_kinds), __sub_rank);
+ __u != dynamic_extent)
+ {
+ constexpr auto __pad = _Trait::template _S_pad<_Mapping, __u>();
+ using _Layout = typename _Trait::template _PaddedLayout<__pad>;
+ return submdspan_mapping_result{
+ typename _Layout::mapping(__sub_exts, __mapping.stride(__u)),
+ __offset};
+ }
+ else
+ {
+ auto __sub_strides
+ = __mdspan::__substrides<_SubExts>(__mapping, __slices...);
+ return submdspan_mapping_result{
+ layout_stride::mapping(__sub_exts, __sub_strides), __offset};
+ }
+ }
+#endif // __glibcxx_submdspan
+ }
+
+ template<typename _Extents>
+ class layout_left::mapping
+ {
+ public:
+ using extents_type = _Extents;
+ using index_type = typename extents_type::index_type;
+ using size_type = typename extents_type::size_type;
+ using rank_type = typename extents_type::rank_type;
+ using layout_type = layout_left;
+
+ static_assert(__mdspan::__representable_size<extents_type, index_type>,
+ "The size of extents_type must be representable as index_type");
+
+ constexpr
+ mapping() noexcept = default;
+
+ constexpr
+ mapping(const mapping&) noexcept = default;
+
+ constexpr
+ mapping(const extents_type& __extents) noexcept
+ : _M_extents(__extents)
+ { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
+
+ template<typename _OExtents>
+ requires is_constructible_v<extents_type, _OExtents>
+ constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
+ mapping(const mapping<_OExtents>& __other) noexcept
+ : mapping(__other.extents(), __mdspan::__internal_ctor{})
+ { }
+
+ template<typename _OExtents>
+ requires (extents_type::rank() <= 1)
+ && is_constructible_v<extents_type, _OExtents>
+ constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
+ mapping(const layout_right::mapping<_OExtents>& __other) noexcept
+ : mapping(__other.extents(), __mdspan::__internal_ctor{})
+ { }
+
+ // noexcept for consistency with other layouts.
+ template<typename _OExtents>
+ requires is_constructible_v<extents_type, _OExtents>
+ constexpr explicit(!(extents_type::rank() == 0
+ && is_convertible_v<_OExtents, extents_type>))
+ mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
+ : mapping(__other.extents(), __mdspan::__internal_ctor{})
+ { __glibcxx_assert(*this == __other); }
+
+#if __glibcxx_padded_layouts
+ template<typename _LeftpadMapping>
+ requires __mdspan::__is_left_padded_mapping<_LeftpadMapping>
+ && is_constructible_v<extents_type,
+ typename _LeftpadMapping::extents_type>
+ constexpr
+ explicit(!is_convertible_v<typename _LeftpadMapping::extents_type,
+ extents_type>)
+ mapping(const _LeftpadMapping& __other) noexcept
+ : mapping(__other.extents(), __mdspan::__internal_ctor{})
+ {
+ constexpr size_t __ostride_sta
+ = __mdspan::__get_static_stride<_LeftpadMapping>();
+
+ if constexpr (extents_type::rank() > 1)
+ {
+ if constexpr (extents_type::static_extent(0) != dynamic_extent
+ && __ostride_sta != dynamic_extent)
+ static_assert(extents_type::static_extent(0) == __ostride_sta);
+ else
+ __glibcxx_assert(__other.stride(1)
+ == __other.extents().extent(0));
+ }
+ }
+#endif // __glibcxx_padded_layouts
+
+ constexpr mapping&
+ operator=(const mapping&) noexcept = default;
+
+ constexpr const extents_type&
+ extents() const noexcept { return _M_extents; }
+
+ constexpr index_type
+ required_span_size() const noexcept
+ { return __mdspan::__size(_M_extents); }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4314. Missing move in mdspan layout mapping::operator()
+ template<__mdspan::__valid_index_type<index_type>... _Indices>
+ requires (sizeof...(_Indices) == extents_type::rank())
+ constexpr index_type
+ operator()(_Indices... __indices) const noexcept
+ {
+ return __mdspan::__linear_index_left(_M_extents,
+ static_cast<index_type>(std::move(__indices))...);
+ }
+
+ static constexpr bool
+ is_always_unique() noexcept { return true; }
+
+ static constexpr bool
+ is_always_exhaustive() noexcept { return true; }
+
+ static constexpr bool
+ is_always_strided() noexcept { return true; }
+
+ static constexpr bool
+ is_unique() noexcept { return true; }
+
+ static constexpr bool
+ is_exhaustive() noexcept { return true; }
+
+ static constexpr bool
+ is_strided() noexcept { return true; }
+
+ constexpr index_type
+ stride(rank_type __i) const noexcept
+ requires (extents_type::rank() > 0)
+ {
+ __glibcxx_assert(__i < extents_type::rank());
+ return __mdspan::__fwd_prod(_M_extents, __i);
+ }
+
+ template<typename _OExtents>
+ requires (extents_type::rank() == _OExtents::rank())
+ friend constexpr bool
+ operator==(const mapping& __self, const mapping<_OExtents>& __other)
+ noexcept
+ { return __self.extents() == __other.extents(); }
+
+ private:
+ template<typename _OExtents>
+ constexpr explicit
+ mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
+ : _M_extents(__oexts)
+ {
+ static_assert(__mdspan::__representable_size<_OExtents, index_type>,
+ "The size of OtherExtents must be representable as index_type");
+ __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
+ }
+
+#if __glibcxx_submdspan
+ template<typename... _Slices>
+ requires (extents_type::rank() == sizeof...(_Slices))
+ friend constexpr auto
+ submdspan_mapping(const mapping& __mapping, _Slices... __slices)
+ { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
+#endif // __glibcxx_submdspan
+
+ [[no_unique_address]] extents_type _M_extents{};
+ };
+
+ namespace __mdspan
+ {
+ template<typename _Extents, typename... _Indices>
+ constexpr typename _Extents::index_type
+ __linear_index_right(const _Extents& __exts, _Indices... __indices)
+ noexcept
+ {
+ using _IndexType = typename _Extents::index_type;
+ array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...};
+ _IndexType __res = 0;
+ if constexpr (sizeof...(__indices) > 0)
+ {
+ _IndexType __mult = 1;
+ auto __update = [&, __pos = __exts.rank()](_IndexType) mutable
+ {
+ --__pos;
+ _GLIBCXX_DEBUG_ASSERT(cmp_less(__ind_arr[__pos],
+ __exts.extent(__pos)));
+ __res += __ind_arr[__pos] * __mult;
+ __mult *= __exts.extent(__pos);
+ };
+ (__update(__indices), ...);
+ }
+ return __res;
+ }
+ }
+
+ template<typename _Extents>
+ class layout_right::mapping
+ {
+ public:
+ using extents_type = _Extents;
+ using index_type = typename extents_type::index_type;
+ using size_type = typename extents_type::size_type;
+ using rank_type = typename extents_type::rank_type;
+ using layout_type = layout_right;
+
+ static_assert(__mdspan::__representable_size<extents_type, index_type>,
+ "The size of extents_type must be representable as index_type");
+
+ constexpr
+ mapping() noexcept = default;
+
+ constexpr
+ mapping(const mapping&) noexcept = default;
+
+ constexpr
+ mapping(const extents_type& __extents) noexcept
+ : _M_extents(__extents)
+ { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
+
+ template<typename _OExtents>
+ requires is_constructible_v<extents_type, _OExtents>
+ constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
+ mapping(const mapping<_OExtents>& __other) noexcept
+ : mapping(__other.extents(), __mdspan::__internal_ctor{})
+ { }
+
+ template<typename _OExtents>
+ requires (extents_type::rank() <= 1)
+ && is_constructible_v<extents_type, _OExtents>
+ constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
+ mapping(const layout_left::mapping<_OExtents>& __other) noexcept
+ : mapping(__other.extents(), __mdspan::__internal_ctor{})
+ { }
+
+ template<typename _OExtents>
+ requires is_constructible_v<extents_type, _OExtents>
+ constexpr explicit(!(extents_type::rank() == 0
+ && is_convertible_v<_OExtents, extents_type>))
+ mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
+ : mapping(__other.extents(), __mdspan::__internal_ctor{})
+ { __glibcxx_assert(*this == __other); }
+
+#if __glibcxx_padded_layouts
+ template<typename _RightPaddedMapping>
+ requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping>
+ && is_constructible_v<extents_type,
+ typename _RightPaddedMapping::extents_type>
+ constexpr
+ explicit(!is_convertible_v<typename _RightPaddedMapping::extents_type,
+ extents_type>)
+ mapping(const _RightPaddedMapping& __other) noexcept
+ : mapping(__other.extents(), __mdspan::__internal_ctor{})
+ {
+ constexpr size_t __rank = extents_type::rank();
+ constexpr size_t __ostride_sta
+ = __mdspan::__get_static_stride<_RightPaddedMapping>();
+
+ if constexpr (__rank > 1)
+ {
+ if constexpr (extents_type::static_extent(__rank - 1) != dynamic_extent
+ && __ostride_sta != dynamic_extent)
+ static_assert(extents_type::static_extent(__rank - 1)
+ == __ostride_sta);
+ else
+ __glibcxx_assert(__other.stride(__rank - 2)
+ == __other.extents().extent(__rank - 1));
+ }
+ }
+#endif
+
+ constexpr mapping&
+ operator=(const mapping&) noexcept = default;
+
+ constexpr const extents_type&
+ extents() const noexcept { return _M_extents; }
+
+ constexpr index_type
+ required_span_size() const noexcept
+ { return __mdspan::__size(_M_extents); }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4314. Missing move in mdspan layout mapping::operator()
+ template<__mdspan::__valid_index_type<index_type>... _Indices>
+ requires (sizeof...(_Indices) == extents_type::rank())
+ constexpr index_type
+ operator()(_Indices... __indices) const noexcept
+ {
+ return __mdspan::__linear_index_right(
+ _M_extents, static_cast<index_type>(std::move(__indices))...);
+ }
+
+ static constexpr bool
+ is_always_unique() noexcept
+ { return true; }
+
+ static constexpr bool
+ is_always_exhaustive() noexcept
+ { return true; }
+
+ static constexpr bool
+ is_always_strided() noexcept
+ { return true; }
+
+ static constexpr bool
+ is_unique() noexcept
+ { return true; }
+
+ static constexpr bool
+ is_exhaustive() noexcept
+ { return true; }
+
+ static constexpr bool
+ is_strided() noexcept
+ { return true; }
+
+ constexpr index_type
+ stride(rank_type __i) const noexcept
+ requires (extents_type::rank() > 0)
+ {
+ __glibcxx_assert(__i < extents_type::rank());
+ return __mdspan::__rev_prod(_M_extents, __i);
+ }
+
+ template<typename _OExtents>
+ requires (extents_type::rank() == _OExtents::rank())
+ friend constexpr bool
+ operator==(const mapping& __self, const mapping<_OExtents>& __other)
+ noexcept
+ { return __self.extents() == __other.extents(); }
+
+ private:
+ template<typename _OExtents>
+ constexpr explicit
+ mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
+ : _M_extents(__oexts)
+ {
+ static_assert(__mdspan::__representable_size<_OExtents, index_type>,
+ "The size of OtherExtents must be representable as index_type");
+ __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
+ }
+
+#if __glibcxx_submdspan
+ template<typename... _Slices>
+ requires (extents_type::rank() == sizeof...(_Slices))
+ friend constexpr auto
+ submdspan_mapping(const mapping& __mapping, _Slices... __slices)
+ { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
+#endif // __glibcxx_submdspan
+
+ [[no_unique_address]] extents_type _M_extents{};
+ };
+
+ namespace __mdspan
+ {
+ template<typename _Mp>
+ concept __mapping_alike = requires
+ {
+ requires __is_extents<typename _Mp::extents_type>;
+ { _Mp::is_always_strided() } -> same_as<bool>;
+ { _Mp::is_always_exhaustive() } -> same_as<bool>;
+ { _Mp::is_always_unique() } -> same_as<bool>;
+ bool_constant<_Mp::is_always_strided()>::value;
+ bool_constant<_Mp::is_always_exhaustive()>::value;
+ bool_constant<_Mp::is_always_unique()>::value;
+ };
+
+ template<typename _Mapping, typename... _Indices>
+ constexpr typename _Mapping::index_type
+ __linear_index_strides(const _Mapping& __m, _Indices... __indices)
+ noexcept
+ {
+ using _IndexType = typename _Mapping::index_type;
+ _IndexType __res = 0;
+ if constexpr (sizeof...(__indices) > 0)
+ {
+ auto __update = [&, __pos = 0u](_IndexType __idx) mutable
+ {
+ _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx,
+ __m.extents().extent(__pos)));
+ __res += __idx * __m.stride(__pos++);
+ };
+ (__update(__indices), ...);
+ }
+ return __res;
+ }
+ }
+
+ template<typename _Extents>
+ class layout_stride::mapping
+ {
+ public:
+ using extents_type = _Extents;
+ using index_type = typename extents_type::index_type;
+ using size_type = typename extents_type::size_type;
+ using rank_type = typename extents_type::rank_type;
+ using layout_type = layout_stride;
+
+ static_assert(__mdspan::__representable_size<extents_type, index_type>,
+ "The size of extents_type must be representable as index_type");
+
+ constexpr
+ mapping() noexcept
+ {
+ // The precondition is either statically asserted, or automatically
+ // satisfied because dynamic extents are zero-initialized.
+ size_t __stride = 1;
+ for (size_t __i = extents_type::rank(); __i > 0; --__i)
+ {
+ _M_strides[__i - 1] = index_type(__stride);
+ __stride *= size_t(_M_extents.extent(__i - 1));
+ }
+ }
+
+ constexpr
+ mapping(const mapping&) noexcept = default;
+
+ template<typename _OIndexType>
+ requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
+ constexpr
+ mapping(const extents_type& __exts,
+ span<_OIndexType, extents_type::rank()> __strides) noexcept
+ : _M_extents(__exts)
+ {
+ for (size_t __i = 0; __i < extents_type::rank(); ++__i)
+ _M_strides[__i] = index_type(as_const(__strides[__i]));
+ }
+
+ template<typename _OIndexType>
+ requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
+ constexpr
+ mapping(const extents_type& __exts,
+ const array<_OIndexType, extents_type::rank()>& __strides)
+ noexcept
+ : mapping(__exts,
+ span<const _OIndexType, extents_type::rank()>(__strides))
+ { }
+
+ template<__mdspan::__mapping_alike _StridedMapping>
+ requires (is_constructible_v<extents_type,
+ typename _StridedMapping::extents_type>
+ && _StridedMapping::is_always_unique()
+ && _StridedMapping::is_always_strided())
+ constexpr explicit(!(
+ is_convertible_v<typename _StridedMapping::extents_type, extents_type>
+ && __mdspan::__standardized_mapping<_StridedMapping>))
+ mapping(const _StridedMapping& __other) noexcept
+ : _M_extents(__other.extents())
+ {
+ using _OIndexType = _StridedMapping::index_type;
+ using _OExtents = _StridedMapping::extents_type;
+
+ __glibcxx_assert(__mdspan::__offset(__other) == 0);
+ static_assert(__mdspan::__representable_size<_OExtents, index_type>,
+ "The size of StridedMapping::extents_type must be representable as"
+ " index_type");
+ if constexpr (cmp_greater(__gnu_cxx::__int_traits<_OIndexType>::__max,
+ __gnu_cxx::__int_traits<index_type>::__max))
+ __glibcxx_assert(!cmp_less(
+ __gnu_cxx::__int_traits<index_type>::__max,
+ __other.required_span_size())
+ && "other.required_span_size() must be representable"
+ " as index_type");
+ if constexpr (extents_type::rank() > 0)
+ for (size_t __i = 0; __i < extents_type::rank(); ++__i)
+ _M_strides[__i] = index_type(__other.stride(__i));
+ }
+
+ constexpr mapping&
+ operator=(const mapping&) noexcept = default;
+
+ constexpr const extents_type&
+ extents() const noexcept { return _M_extents; }
+
+ constexpr array<index_type, extents_type::rank()>
+ strides() const noexcept
+ {
+ array<index_type, extents_type::rank()> __ret;
+ for (size_t __i = 0; __i < extents_type::rank(); ++__i)
+ __ret[__i] = _M_strides[__i];
+ return __ret;
+ }
+
+ constexpr index_type
+ required_span_size() const noexcept
+ {
+ if (__mdspan::__empty(_M_extents))
+ return 0;
+
+ index_type __ret = 1;
+ for (size_t __i = 0; __i < extents_type::rank(); ++__i)
+ __ret += (_M_extents.extent(__i) - 1) * _M_strides[__i];
+ return __ret;
+ }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4314. Missing move in mdspan layout mapping::operator()
+ template<__mdspan::__valid_index_type<index_type>... _Indices>
+ requires (sizeof...(_Indices) == extents_type::rank())
+ constexpr index_type
+ operator()(_Indices... __indices) const noexcept
+ {
+ return __mdspan::__linear_index_strides(*this,
+ static_cast<index_type>(std::move(__indices))...);
+ }
+
+ static constexpr bool
+ is_always_unique() noexcept { return true; }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4266. layout_stride::mapping should treat empty mappings as exhaustive
+ static constexpr bool
+ is_always_exhaustive() noexcept
+ {
+ return (_Extents::rank() == 0) || __mdspan::__contains_zero(
+ __mdspan::__static_extents<extents_type>());
+ }
+
+ static constexpr bool
+ is_always_strided() noexcept { return true; }
+
+ static constexpr bool
+ is_unique() noexcept { return true; }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4266. layout_stride::mapping should treat empty mappings as exhaustive
+ constexpr bool
+ is_exhaustive() const noexcept
+ {
+ if constexpr (!is_always_exhaustive())
+ {
+ auto __size = __mdspan::__size(_M_extents);
+ if(__size > 0)
+ return __size == required_span_size();
+ }
+ return true;
+ }
+
+ static constexpr bool
+ is_strided() noexcept { return true; }
+
+ constexpr index_type
+ stride(rank_type __r) const noexcept { return _M_strides[__r]; }
+
+ template<__mdspan::__mapping_alike _OMapping>
+ requires ((extents_type::rank() == _OMapping::extents_type::rank())
+ && _OMapping::is_always_strided())
+ friend constexpr bool
+ operator==(const mapping& __self, const _OMapping& __other) noexcept
+ {
+ if (__self.extents() != __other.extents())
+ return false;
+ if constexpr (extents_type::rank() > 0)
+ for (size_t __i = 0; __i < extents_type::rank(); ++__i)
+ if (!cmp_equal(__self.stride(__i), __other.stride(__i)))
+ return false;
+ return __mdspan::__offset(__other) == 0;
+ }
+
+ private:
+#if __glibcxx_submdspan
+ template<typename... _Slices>
+ requires (extents_type::rank() == sizeof...(_Slices))
+ friend constexpr auto
+ submdspan_mapping(const mapping& __mapping, _Slices... __slices)
+ {
+ if constexpr (sizeof...(_Slices) == 0)
+ return submdspan_mapping_result{__mapping, 0};
+ else
+ {
+ auto __offset = __mdspan::__suboffset(__mapping, __slices...);
+ auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...);
+ auto __sub_strides
+ = __mdspan::__substrides<decltype(__sub_exts)>(__mapping, __slices...);
+ return submdspan_mapping_result{
+ layout_stride::mapping(__sub_exts, __sub_strides), __offset};
+ }
+ }
+#endif
+
+ using _Strides = typename __array_traits<index_type,
+ extents_type::rank()>::_Type;
+ [[no_unique_address]] extents_type _M_extents;
+ [[no_unique_address]] _Strides _M_strides;
+ };
+
+#ifdef __glibcxx_padded_layouts
+ namespace __mdspan
+ {
+ constexpr size_t
+ __least_multiple(size_t __x, size_t __y)
+ {
+ if (__x <= 1)
+ return __y;
+ return (__y / __x + (__y % __x != 0)) * __x ;
+ }
+
+ template<typename _IndexType>
+ constexpr bool
+ __is_representable_least_multiple(size_t __x, size_t __y)
+ {
+ constexpr auto __y_max = __gnu_cxx::__int_traits<_IndexType>::__max;
+ if(std::cmp_greater(__y, __y_max))
+ return false;
+
+ if(__x <= 1)
+ return true;
+
+ auto __max_delta = __y_max - static_cast<_IndexType>(__y);
+ auto __y_mod_x = __y % __x;
+ auto __delta = (__y_mod_x == 0) ? size_t(0) : (__x - __y_mod_x);
+ return std::cmp_less_equal(__delta, __max_delta);
+ }
+
+ template<typename _Extents, size_t _PaddingValue, typename _LayoutTraits,
+ size_t _Rank = _Extents::rank()>
+ concept __valid_static_stride = (_Extents::rank() <= 1)
+ || (_PaddingValue == dynamic_extent)
+ || (_Extents::static_extent(_LayoutTraits::_S_ext_idx) == dynamic_extent)
+ || (__is_representable_least_multiple<size_t>(
+ _PaddingValue, _Extents::static_extent(_LayoutTraits::_S_ext_idx)));
+
+ template<size_t _PaddedStride, typename _Extents,
+ typename _LayoutTraits>
+ consteval bool
+ __is_representable_padded_size()
+ {
+ using _IndexType = typename _Extents::index_type;
+ auto __sta_exts = __static_extents<_Extents>(
+ _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end);
+ size_t __max = __gnu_cxx::__int_traits<_IndexType>::__max;
+ return __static_quotient(__sta_exts, __max / _PaddedStride) != 0;
+ }
+
+ template<typename _Extents, size_t _PaddedStride, typename _LayoutTraits,
+ size_t _Rank = _Extents::rank()>
+ concept __valid_padded_size = (_Rank <= 1)
+ || (_PaddedStride == dynamic_extent)
+ || (!__all_static(__static_extents<_Extents>()))
+ || (__contains_zero(__static_extents<_Extents>()))
+ || (__is_representable_padded_size<_PaddedStride, _Extents,
+ _LayoutTraits>());
+
+ template<typename _Extents, typename _Stride, typename... _Indices>
+ constexpr typename _Extents::index_type
+ __linear_index_leftpad(const _Extents& __exts, _Stride __stride,
+ _Indices... __indices)
+ {
+ // i0 + stride*(i1 + extents.extent(1)*...)
+ using _IndexType = typename _Extents::index_type;
+ _IndexType __res = 0;
+ if constexpr (sizeof...(__indices) > 0)
+ {
+ _IndexType __mult = 1;
+
+ auto __update_rest = [&, __pos = 1u](_IndexType __idx) mutable
+ {
+ __res += __idx * __mult;
+ __mult *= __exts.extent(__pos);
+ ++__pos;
+ };
+
+ auto __update = [&](_IndexType __idx, auto... __rest)
+ {
+ __res += __idx;
+ __mult = __stride.extent(0);
+ (__update_rest(__rest), ...);
+ };
+ __update(__indices...);
+ }
+ return __res;
+ }
+
+ template<typename _Extents, typename _Stride, typename... _Indices>
+ constexpr typename _Extents::index_type
+ __linear_index_rightpad(const _Extents& __exts, _Stride __stride,
+ _Indices... __indices)
+ {
+ // i[n-1] + stride*(i[n-2] + extents.extent(n-2])*...)
+ using _IndexType = typename _Extents::index_type;
+ _IndexType __res = 0;
+ if constexpr (sizeof...(__indices) > 0)
+ {
+ _IndexType __mult = 1;
+ array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...};
+
+ auto __update_rest = [&, __pos = __exts.rank()-1](_IndexType) mutable
+ {
+ --__pos;
+ __res += __ind_arr[__pos] * __mult;
+ __mult *= __exts.extent(__pos);
+ };
+
+ auto __update = [&](_IndexType, auto... __rest)
+ {
+ __res += __ind_arr[__exts.rank() - 1];
+ __mult = __stride.extent(0);
+ (__update_rest(__rest), ...);
+ };
+ __update(__indices...);
+ }
+ return __res;
+ }
+
+ template<size_t _Rank>
+ struct _LeftPaddedLayoutTraits
+ {
+ using _LayoutSame = layout_left;
+ using _LayoutOther = layout_right;
+
+ constexpr static const size_t _S_ext_idx = 0;
+ constexpr static const size_t _S_stride_idx = 1;
+ constexpr static const size_t _S_unpad_begin = 1;
+ constexpr static const size_t _S_unpad_end = _Rank;
+
+ template<typename _IndexType, size_t _StaticStride, size_t..._Extents>
+ constexpr static auto
+ _S_make_padded_extent(
+ extents<_IndexType, _StaticStride> __stride,
+ const extents<_IndexType, _Extents...>& __exts)
+ {
+ auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>)
+ {
+ return extents<_IndexType, _StaticStride,
+ (_Extents...[_Is + 1])...>{
+ __stride.extent(0), __exts.extent(_Is + 1)...};
+ };
+ return __impl(make_index_sequence<sizeof...(_Extents) - 1>());
+ }
+ };
+
+ template<size_t _Rank>
+ struct _RightPaddedLayoutTraits
+ {
+ using _LayoutSame = layout_right;
+ using _LayoutOther = layout_left;
+
+ constexpr static size_t _S_ext_idx = _Rank - 1;
+ constexpr static size_t _S_stride_idx = _Rank - 2;
+ constexpr static size_t _S_unpad_begin = 0;
+ constexpr static size_t _S_unpad_end = _Rank - 1;
+
+ template<typename _IndexType, size_t _StaticStride, size_t..._Extents>
+ constexpr static auto
+ _S_make_padded_extent(
+ extents<_IndexType, _StaticStride> __stride,
+ const extents<_IndexType, _Extents...>& __exts)
+ {
+ auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>)
+ {
+ return extents<_IndexType, (_Extents...[_Is])..., _StaticStride>{
+ __exts.extent(_Is)..., __stride.extent(0)};
+ };
+ return __impl(make_index_sequence<sizeof...(_Extents) - 1>());
+ }
+ };
+
+ template<size_t _PaddingValue, typename _Extents, typename _LayoutTraits>
+ class _PaddedStorage
+ {
+ using _LayoutSame = typename _LayoutTraits::_LayoutSame;
+
+ public:
+ using _IndexType = typename _Extents::index_type;
+ constexpr static size_t _S_rank = _Extents::rank();
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4372. Weaken Mandates: for dynamic padding values in padded layouts
+ static_assert((_PaddingValue == dynamic_extent)
+ || (cmp_less_equal(_PaddingValue,
+ __gnu_cxx::__int_traits<_IndexType>::__max)),
+ "padding_value must be representable as index_type");
+
+ static_assert(__representable_size<_Extents, _IndexType>,
+ "The size of extents_type must be representable as index_type");
+
+ static_assert(__valid_static_stride<_Extents, _PaddingValue,
+ _LayoutTraits>,
+ "The padded stride must be representable as size_t");
+
+ static constexpr size_t _S_static_stride = [] consteval
+ {
+ constexpr size_t __rank = _Extents::rank();
+ if constexpr (__rank <= 1)
+ return 0;
+ else
+ {
+ constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
+ constexpr size_t __sta_ext = _Extents::static_extent(__ext_idx);
+ if constexpr (__sta_ext == 0)
+ return size_t(0);
+ else if constexpr (_PaddingValue == dynamic_extent
+ || __sta_ext == dynamic_extent)
+ return dynamic_extent;
+ else
+ return __least_multiple(_PaddingValue, __sta_ext);
+ }
+ }();
+
+ static_assert(_S_static_stride == dynamic_extent
+ || cmp_less_equal(_S_static_stride,
+ __gnu_cxx::__int_traits<_IndexType>::__max),
+ "Padded stride must be representable as index_type");
+
+ static_assert(__valid_padded_size<_Extents, _S_static_stride,
+ _LayoutTraits>);
+
+ constexpr
+ _PaddedStorage() noexcept
+ {
+ if constexpr (_S_rank > 1)
+ if constexpr (_S_static_stride == dynamic_extent
+ && _S_static_padextent() != dynamic_extent)
+ _M_stride = _Stride{_S_static_padextent()};
+ }
+
+ constexpr explicit
+ _PaddedStorage(const _Extents& __exts)
+ : _M_extents(__exts)
+ {
+ if constexpr (!__all_static(__static_extents<_Extents>()))
+ __glibcxx_assert(__is_representable_extents(_M_extents));
+
+ if constexpr (_S_rank > 1)
+ {
+ _IndexType __stride;
+ if constexpr (_PaddingValue == dynamic_extent)
+ __stride = _M_padextent();
+ else if constexpr (_S_static_padextent() != dynamic_extent)
+ return;
+ else
+ {
+ __glibcxx_assert(
+ __is_representable_least_multiple<_IndexType>(
+ _PaddingValue, _M_padextent()));
+
+ __stride = static_cast<_IndexType>(
+ __least_multiple(_PaddingValue, _M_padextent()));
+
+ __glibcxx_assert(__is_representable_extents(
+ _LayoutTraits::_S_make_padded_extent(
+ std::dextents<_IndexType, 1>{__stride},
+ _M_extents)));
+ }
+ _M_stride = _Stride{__stride};
+ }
+ }
+
+ constexpr explicit
+ _PaddedStorage(const _Extents& __exts, _IndexType __pad)
+ : _M_extents(__exts)
+ {
+ if constexpr (_PaddingValue != dynamic_extent)
+ __glibcxx_assert(cmp_equal(_PaddingValue, __pad));
+ if constexpr (_S_rank > 1 && _S_static_stride == dynamic_extent)
+ {
+ __glibcxx_assert(
+ __is_representable_least_multiple<_IndexType>(
+ __pad, _M_padextent()));
+
+ _M_stride = _Stride{static_cast<_IndexType>(
+ __least_multiple(__pad, _M_padextent()))};
+
+ __glibcxx_assert(__is_representable_extents(
+ _LayoutTraits::_S_make_padded_extent(
+ _M_stride, _M_extents)));
+ }
+ }
+
+ template<typename _OExtents>
+ constexpr explicit
+ _PaddedStorage(
+ const typename _LayoutSame::template mapping<_OExtents>& __other)
+ : _PaddedStorage(_Extents(__other.extents()))
+ {
+ constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
+ constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
+ if constexpr (_S_rank > 1 && _PaddingValue != dynamic_extent)
+ {
+ static_assert(_S_static_stride == dynamic_extent
+ || _OExtents::static_extent(__ext_idx) == dynamic_extent
+ || _S_static_stride == _OExtents::static_extent(__ext_idx),
+ "The padded stride must be compatible with other");
+
+ if constexpr (_S_static_stride == dynamic_extent
+ || _OExtents::static_extent(__stride_idx) == dynamic_extent)
+ __glibcxx_assert(std::cmp_equal(_M_padstride(),
+ _M_padextent()));
+ }
+ }
+
+ template<typename _OExtents>
+ constexpr explicit
+ _PaddedStorage(const typename layout_stride::mapping<_OExtents>&
+ __other)
+ : _M_extents(__other.extents())
+ {
+ __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
+ __gnu_cxx::__int_traits<_IndexType>
+ ::__max));
+
+ constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
+ if constexpr (_S_rank > 1)
+ {
+ if constexpr (_PaddingValue != dynamic_extent)
+ __glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
+ _M_calc_padstride())
+ && "The padded stride must be compatible with other");
+ if constexpr (_S_static_stride == dynamic_extent)
+ _M_stride = _Stride{__other.stride(__stride_idx)};
+ }
+ }
+
+ template<typename _SamePaddedMapping>
+ constexpr explicit
+ _PaddedStorage(_LayoutTraits::_LayoutSame,
+ const _SamePaddedMapping& __other)
+ : _M_extents(__other.extents())
+ {
+ if constexpr (_S_rank > 1)
+ {
+ static_assert(_PaddingValue == dynamic_extent
+ || _SamePaddedMapping::padding_value == dynamic_extent
+ || _PaddingValue == _SamePaddedMapping::padding_value,
+ "If neither PaddingValue is dynamic_extent, then they must "
+ "be equal");
+
+ constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
+ if constexpr (_PaddingValue != dynamic_extent)
+ __glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
+ _M_calc_padstride())
+ && "The padded stride must be compatible with other");
+ if constexpr (_S_static_stride == dynamic_extent)
+ _M_stride = _Stride{__other.stride(__stride_idx)};
+ }
+ __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
+ __gnu_cxx::__int_traits<_IndexType>::__max));
+ }
+
+ template<typename _OtherPaddedMapping>
+ constexpr explicit
+ _PaddedStorage(_LayoutTraits::_LayoutOther,
+ const _OtherPaddedMapping& __other) noexcept
+ : _M_extents(__other.extents())
+ {
+ __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
+ __gnu_cxx::__int_traits<_IndexType>::__max));
+ }
+
+ static constexpr bool
+ _M_is_always_exhaustive() noexcept
+ {
+ if constexpr (_S_rank <= 1)
+ return true;
+ else
+ return _S_static_padextent() != dynamic_extent
+ && _S_static_stride != dynamic_extent
+ && _S_static_padextent() == _S_static_stride;
+ }
+
+ constexpr bool
+ _M_is_exhaustive() const noexcept
+ {
+ if constexpr (_M_is_always_exhaustive())
+ return true;
+ else
+ return cmp_equal(_M_padextent(), _M_padstride());
+ }
+
+ constexpr static size_t
+ _S_static_padextent() noexcept
+ { return _Extents::static_extent(_LayoutTraits::_S_ext_idx); }
+
+ constexpr _IndexType
+ _M_padextent() const noexcept
+ { return _M_extents.extent(_LayoutTraits::_S_ext_idx); }
+
+ constexpr _IndexType
+ _M_calc_padstride() const noexcept
+ {
+ if constexpr (_S_static_stride != dynamic_extent)
+ return _S_static_stride;
+ else if constexpr (_PaddingValue != dynamic_extent)
+ return __least_multiple(_PaddingValue, _M_padextent());
+ else
+ return _M_padextent();
+ }
+
+ constexpr _IndexType
+ _M_padstride() const noexcept
+ { return _M_stride.extent(0); }
+
+ constexpr _IndexType
+ _M_required_span_size() const noexcept
+ {
+ if constexpr (_S_rank == 0)
+ return 1;
+ else if (__mdspan::__empty(_M_extents))
+ return 0;
+ else
+ {
+ size_t __stride = static_cast<size_t>(_M_padstride());
+ size_t __prod_rest = __mdspan::__fwd_prod(_M_extents,
+ _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end);
+ size_t __delta = _M_padstride() - _M_padextent();
+ return static_cast<_IndexType>(__stride * __prod_rest - __delta);
+ }
+ }
+
+ template<typename _SamePaddedMapping>
+ constexpr bool
+ _M_equal(const _SamePaddedMapping& __other) const noexcept
+ {
+ return _M_extents == __other.extents()
+ && (_S_rank < 2
+ || cmp_equal(_M_stride.extent(0),
+ __other.stride(_LayoutTraits::_S_stride_idx)));
+ }
+
+ using _Stride = std::extents<_IndexType, _S_static_stride>;
+ [[no_unique_address]] _Stride _M_stride;
+ [[no_unique_address]] _Extents _M_extents;
+ };
+ }
+
+ template<size_t _PaddingValue>
+ template<typename _Extents>
+ class layout_left_padded<_PaddingValue>::mapping
+ {
+ public:
+ static constexpr size_t padding_value = _PaddingValue;
+
+ using extents_type = _Extents;
+ using index_type = typename extents_type::index_type;
+ using size_type = typename extents_type::size_type;
+ using rank_type = typename extents_type::rank_type;
+ using layout_type = layout_left_padded<padding_value>;
+
+ private:
+ static constexpr size_t _S_rank = extents_type::rank();
+ using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
+ _Extents, __mdspan::_LeftPaddedLayoutTraits<_S_rank>>;
+ [[no_unique_address]] _PaddedStorage _M_storage;
+
+ consteval friend size_t
+ __mdspan::__get_static_stride<mapping>();
+
+ constexpr index_type
+ _M_extent(size_t __r) const noexcept
+ { return _M_storage._M_extents.extent(__r); }
+
+ constexpr index_type
+ _M_padstride() const noexcept
+ { return _M_storage._M_stride.extent(0); }
+
+ public:
+ constexpr
+ mapping() noexcept
+ { }
+
+ constexpr
+ mapping(const mapping&) noexcept = default;
+
+ constexpr
+ mapping(const extents_type& __exts)
+ : _M_storage(__exts)
+ { }
+
+ template<__mdspan::__valid_index_type<index_type> _OIndexType>
+ constexpr
+ mapping(const extents_type& __exts, _OIndexType __pad)
+ : _M_storage(__exts,
+ __mdspan::__index_type_cast<index_type>(std::move(__pad)))
+ { }
+
+ template<typename _OExtents>
+ requires is_constructible_v<extents_type, _OExtents>
+ constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
+ mapping(const layout_left::mapping<_OExtents>& __other)
+ : _M_storage(__other)
+ { }
+
+ template<typename _OExtents>
+ requires is_constructible_v<_OExtents, extents_type>
+ constexpr explicit(!(_OExtents::rank() == 0
+ && is_convertible_v<_OExtents, extents_type>))
+ mapping(const typename layout_stride::mapping<_OExtents>& __other)
+ : _M_storage(__other)
+ { __glibcxx_assert(*this == __other); }
+
+ template<typename _LeftPaddedMapping>
+ requires __mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
+ && is_constructible_v<extents_type,
+ typename _LeftPaddedMapping::extents_type>
+ constexpr explicit(
+ !is_convertible_v<typename _LeftPaddedMapping::extents_type,
+ extents_type>
+ || _S_rank > 1 && (padding_value != dynamic_extent
+ || _LeftPaddedMapping::padding_value == dynamic_extent))
+ mapping(const _LeftPaddedMapping& __other)
+ : _M_storage(layout_left{}, __other)
+ { }
+
+ template<typename _RightPaddedMapping>
+ requires (__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
+ || __mdspan::__mapping_of<layout_right, _RightPaddedMapping>)
+ && (_S_rank <= 1)
+ && is_constructible_v<extents_type,
+ typename _RightPaddedMapping::extents_type>
+ constexpr explicit(!is_convertible_v<
+ typename _RightPaddedMapping::extents_type, extents_type>)
+ mapping(const _RightPaddedMapping& __other) noexcept
+ : _M_storage(layout_right{}, __other)
+ { }
+
+ constexpr mapping&
+ operator=(const mapping&) noexcept = default;
+
+ constexpr const extents_type&
+ extents() const noexcept { return _M_storage._M_extents; }
+
+ constexpr array<index_type, _S_rank>
+ strides() const noexcept
+ {
+ array<index_type, _S_rank> __ret;
+ if constexpr (_S_rank > 0)
+ __ret[0] = 1;
+ if constexpr (_S_rank > 1)
+ __ret[1] = _M_padstride();
+ if constexpr (_S_rank > 2)
+ for(size_t __i = 2; __i < _S_rank; ++__i)
+ __ret[__i] = __ret[__i - 1] * _M_extent(__i - 1);
+ return __ret;
+ }
+
+ constexpr index_type
+ required_span_size() const noexcept
+ { return _M_storage._M_required_span_size(); }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4314. Missing move in mdspan layout mapping::operator()
+ template<__mdspan::__valid_index_type<index_type>... _Indices>
+ requires (sizeof...(_Indices) == _S_rank)
+ constexpr index_type
+ operator()(_Indices... __indices) const noexcept
+ {
+ return __mdspan::__linear_index_leftpad(
+ extents(), _M_storage._M_stride,
+ static_cast<index_type>(std::move(__indices))...);
+ }
+
+ static constexpr bool
+ is_always_exhaustive() noexcept
+ { return _PaddedStorage::_M_is_always_exhaustive(); }
+
+ constexpr bool
+ is_exhaustive() noexcept
+ { return _M_storage._M_is_exhaustive(); }
+
+ static constexpr bool
+ is_always_unique() noexcept { return true; }
+
+ static constexpr bool
+ is_unique() noexcept { return true; }
+
+ static constexpr bool
+ is_always_strided() noexcept { return true; }
+
+ static constexpr bool
+ is_strided() noexcept { return true; }
+
+ constexpr index_type
+ stride(rank_type __r) const noexcept
+ {
+ __glibcxx_assert(__r < _S_rank);
+ if (__r == 0)
+ return 1;
+ else
+ return static_cast<index_type>(
+ static_cast<size_t>(_M_padstride()) *
+ static_cast<size_t>(__mdspan::__fwd_prod(extents(), 1, __r)));
+ }
+
+ template<typename _LeftpadMapping>
+ requires(__mdspan::__is_left_padded_mapping<_LeftpadMapping>
+ && _LeftpadMapping::extents_type::rank() == _S_rank)
+ friend constexpr bool
+ operator==(const mapping& __self, const _LeftpadMapping& __other)
+ noexcept
+ { return __self._M_storage._M_equal(__other); }
+
+ private:
+#if __glibcxx_submdspan
+ template<typename... _Slices>
+ requires (extents_type::rank() == sizeof...(_Slices))
+ friend constexpr auto
+ submdspan_mapping(const mapping& __mapping, _Slices... __slices)
+ { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
+#endif // __glibcxx_submdspan
+ };
+
+ template<size_t _PaddingValue>
+ template<typename _Extents>
+ class layout_right_padded<_PaddingValue>::mapping {
+ public:
+ static constexpr size_t padding_value = _PaddingValue;
+ using extents_type = _Extents;
+ using index_type = typename extents_type::index_type;
+ using size_type = typename extents_type::size_type;
+ using rank_type = typename extents_type::rank_type;
+ using layout_type = layout_right_padded<_PaddingValue>;
+
+ private:
+ static constexpr size_t _S_rank = extents_type::rank();
+ using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
+ _Extents, __mdspan::_RightPaddedLayoutTraits<_S_rank>>;
+ [[no_unique_address]] _PaddedStorage _M_storage;
+
+ consteval friend size_t
+ __mdspan::__get_static_stride<mapping>();
+
+ constexpr index_type
+ _M_extent(size_t __r) const noexcept
+ { return _M_storage._M_extents.extent(__r); }
+
+ constexpr index_type
+ _M_padstride() const noexcept
+ { return _M_storage._M_stride.extent(0); }
+
+ public:
+ constexpr
+ mapping() noexcept
+ { }
+
+ constexpr
+ mapping(const mapping&) noexcept = default;
+
+ constexpr
+ mapping(const extents_type& __exts)
+ : _M_storage(__exts)
+ { }
+
+ template<__mdspan::__valid_index_type<index_type> _OIndexType>
+ constexpr
+ mapping(const extents_type& __exts, _OIndexType __pad)
+ : _M_storage(__exts,
+ __mdspan::__index_type_cast<index_type>(std::move(__pad)))
+ { }
+
+ template<typename _OExtents>
+ requires is_constructible_v<extents_type, _OExtents>
+ constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
+ mapping(const layout_right::mapping<_OExtents>& __other)
+ : _M_storage(__other)
+ { }
+
+ template<typename _OExtents>
+ requires is_constructible_v<_OExtents, extents_type>
+ constexpr explicit(!(_OExtents::rank() == 0
+ && is_convertible_v<_OExtents, extents_type>))
+ mapping(const typename layout_stride::mapping<_OExtents>& __other)
+ : _M_storage(__other)
+ { __glibcxx_assert(*this == __other); }
+
+ template<typename _RightPaddedMapping>
+ requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping>
+ && is_constructible_v<extents_type,
+ typename _RightPaddedMapping::extents_type>
+ constexpr explicit(
+ !is_convertible_v<typename _RightPaddedMapping::extents_type,
+ extents_type>
+ || _S_rank > 1 && (padding_value != dynamic_extent
+ || _RightPaddedMapping::padding_value == dynamic_extent))
+ mapping(const _RightPaddedMapping& __other)
+ : _M_storage(layout_right{}, __other)
+ { }
+
+ template<typename _LeftPaddedMapping>
+ requires (__mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
+ || __mdspan::__mapping_of<layout_left, _LeftPaddedMapping>)
+ && (_S_rank <= 1)
+ && is_constructible_v<extents_type,
+ typename _LeftPaddedMapping::extents_type>
+ constexpr explicit(!is_convertible_v<
+ typename _LeftPaddedMapping::extents_type, extents_type>)
+ mapping(const _LeftPaddedMapping& __other) noexcept
+ : _M_storage(layout_left{}, __other)
+ { }
+
+ constexpr mapping& operator=(const mapping&) noexcept = default;
+
+ constexpr const extents_type&
+ extents() const noexcept { return _M_storage._M_extents; }
+
+ constexpr array<index_type, _S_rank>
+ strides() const noexcept
+ {
+ array<index_type, _S_rank> __ret;
+ if constexpr (_S_rank > 0)
+ __ret[_S_rank - 1] = 1;
+ if constexpr (_S_rank > 1)
+ __ret[_S_rank - 2] = _M_padstride();
+ if constexpr (_S_rank > 2)
+ for(size_t __i = _S_rank - 2; __i > 0; --__i)
+ __ret[__i - 1] = __ret[__i] * _M_extent(__i);
+ return __ret;
+ }
+
+ constexpr index_type
+ required_span_size() const noexcept
+ { return _M_storage._M_required_span_size(); }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4314. Missing move in mdspan layout mapping::operator()
+ template<__mdspan::__valid_index_type<index_type>... _Indices>
+ requires (sizeof...(_Indices) == _S_rank)
+ constexpr index_type
+ operator()(_Indices... __indices) const noexcept
+ {
+ return __mdspan::__linear_index_rightpad(
+ extents(), _M_storage._M_stride,
+ static_cast<index_type>(std::move(__indices))...);
+ }
+
+ static constexpr bool
+ is_always_exhaustive() noexcept
+ { return _PaddedStorage::_M_is_always_exhaustive(); }
+
+ constexpr bool
+ is_exhaustive() noexcept
+ { return _M_storage._M_is_exhaustive(); }
+
+ static constexpr bool
+ is_always_unique() noexcept { return true; }
+
+ static constexpr bool
+ is_unique() noexcept { return true; }
+
+ static constexpr bool
+ is_always_strided() noexcept { return true; }
+
+ static constexpr bool
+ is_strided() noexcept { return true; }
+
+ constexpr index_type
+ stride(rank_type __r) const noexcept
+ {
+ __glibcxx_assert(__r < _S_rank);
+ if constexpr (_S_rank <= 1)
+ return 1;
+ else if (__r == _S_rank - 1)
+ return 1;
+ else if (__r == _S_rank - 2)
+ return _M_padstride();
+ else
+ return static_cast<index_type>(
+ static_cast<size_t>(_M_padstride()) *
+ static_cast<size_t>(__mdspan::__fwd_prod(
+ extents(), __r + 1, _S_rank - 1)));
+ }
+
+ template<typename _RightPaddedMapping>
+ requires(__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
+ && _RightPaddedMapping::extents_type::rank() == _S_rank)
+ friend constexpr bool
+ operator==(const mapping& __self, const _RightPaddedMapping& __other)
+ noexcept
+ { return __self._M_storage._M_equal(__other); }
+
+#if __glibcxx_submdspan
+ private:
+ template<typename... _Slices>
+ requires (extents_type::rank() == sizeof...(_Slices))
+ friend constexpr auto
+ submdspan_mapping(const mapping& __mapping, _Slices... __slices)
+ { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
+#endif // __glibcxx_submdspan
+ };
+#endif // __glibcxx_padded_layouts
+
+ template<typename _ElementType>
+ struct default_accessor
+ {
+ static_assert(!is_array_v<_ElementType>,
+ "ElementType must not be an array type");
+ static_assert(!is_abstract_v<_ElementType>,
+ "ElementType must not be an abstract class type");
+
+ using offset_policy = default_accessor;
+ using element_type = _ElementType;
+ using reference = element_type&;
+ using data_handle_type = element_type*;
+
+ constexpr
+ default_accessor() noexcept = default;
+
+ template<typename _OElementType>
+ requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
+ constexpr
+ default_accessor(default_accessor<_OElementType>) noexcept
+ { }
+
+ constexpr reference
+ access(data_handle_type __p, size_t __i) const noexcept
+ { return __p[__i]; }
+
+ constexpr data_handle_type
+ offset(data_handle_type __p, size_t __i) const noexcept
+ { return __p + __i; }
+ };
+
+#ifdef __glibcxx_aligned_accessor
+ template<typename _ElementType, size_t _ByteAlignment>
+ struct aligned_accessor
+ {
+ static_assert(has_single_bit(_ByteAlignment),
+ "ByteAlignment must be a power of two");
+ static_assert(_ByteAlignment >= alignof(_ElementType));
+
+ using offset_policy = default_accessor<_ElementType>;
+ using element_type = _ElementType;
+ using reference = element_type&;
+ using data_handle_type = element_type*;
+
+ static constexpr size_t byte_alignment = _ByteAlignment;
+
+ constexpr
+ aligned_accessor() noexcept = default;
+
+ template<typename _OElementType, size_t _OByteAlignment>
+ requires (_OByteAlignment >= byte_alignment)
+ && is_convertible_v<_OElementType(*)[], element_type(*)[]>
+ constexpr
+ aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>)
+ noexcept
+ { }
+
+ template<typename _OElementType>
+ requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
+ constexpr explicit
+ aligned_accessor(default_accessor<_OElementType>) noexcept
+ { }
+
+ template<typename _OElementType>
+ requires is_convertible_v<element_type(*)[], _OElementType(*)[]>
+ constexpr
+ operator default_accessor<_OElementType>() const noexcept
+ { return {}; }
+
+ constexpr reference
+ access(data_handle_type __p, size_t __i) const noexcept
+ { return std::assume_aligned<byte_alignment>(__p)[__i]; }
+
+ constexpr typename offset_policy::data_handle_type
+ offset(data_handle_type __p, size_t __i) const noexcept
+ { return std::assume_aligned<byte_alignment>(__p) + __i; }
+ };
+#endif
+
+ namespace __mdspan
+ {
+ template<typename _Extents, typename _IndexType, size_t _Nm>
+ constexpr bool
+ __is_multi_index(const _Extents& __exts, span<_IndexType, _Nm> __indices)
+ {
+ static_assert(__exts.rank() == _Nm);
+ for (size_t __i = 0; __i < __exts.rank(); ++__i)
+ if (__indices[__i] >= __exts.extent(__i))
+ return false;
+ return true;
+ }
+ }
+
+ template<typename _ElementType, typename _Extents,
+ typename _LayoutPolicy = layout_right,
+ typename _AccessorPolicy = default_accessor<_ElementType>>
+ class mdspan
+ {
+ static_assert(!is_array_v<_ElementType>,
+ "ElementType must not be an array type");
+ static_assert(!is_abstract_v<_ElementType>,
+ "ElementType must not be an abstract class type");
+ static_assert(__mdspan::__is_extents<_Extents>,
+ "Extents must be a specialization of std::extents");
+ static_assert(is_same_v<_ElementType,
+ typename _AccessorPolicy::element_type>);
+
+ public:
+ using extents_type = _Extents;
+ using layout_type = _LayoutPolicy;
+ using accessor_type = _AccessorPolicy;
+ using mapping_type = typename layout_type::template mapping<extents_type>;
+ using element_type = _ElementType;
+ using value_type = remove_cv_t<element_type>;
+ using index_type = typename extents_type::index_type;
+ using size_type = typename extents_type::size_type;
+ using rank_type = typename extents_type::rank_type;
+ using data_handle_type = typename accessor_type::data_handle_type;
+ using reference = typename accessor_type::reference;
+
+ static constexpr rank_type
+ rank() noexcept { return extents_type::rank(); }
+
+ static constexpr rank_type
+ rank_dynamic() noexcept { return extents_type::rank_dynamic(); }
+
+ static constexpr size_t
+ static_extent(rank_type __r) noexcept
+ { return extents_type::static_extent(__r); }
+
+ constexpr index_type
+ extent(rank_type __r) const noexcept { return extents().extent(__r); }
+
+ constexpr
+ mdspan()
+ requires (rank_dynamic() > 0)
+ && is_default_constructible_v<data_handle_type>
+ && is_default_constructible_v<mapping_type>
+ && is_default_constructible_v<accessor_type> = default;
+
+ constexpr
+ mdspan(const mdspan& __other) = default;
+
+ constexpr
+ mdspan(mdspan&& __other) = default;
+
+ template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
+ requires (sizeof...(_OIndexTypes) == rank()
+ || sizeof...(_OIndexTypes) == rank_dynamic())
+ && is_constructible_v<mapping_type, extents_type>
+ && is_default_constructible_v<accessor_type>
+ constexpr explicit
+ mdspan(data_handle_type __handle, _OIndexTypes... __exts)
+ : _M_accessor(),
+ _M_mapping(_Extents(static_cast<index_type>(std::move(__exts))...)),
+ _M_handle(std::move(__handle))
+ { }
+
+ template<typename _OIndexType, size_t _Nm>
+ requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
+ && (_Nm == rank() || _Nm == rank_dynamic())
+ && is_constructible_v<mapping_type, extents_type>
+ && is_default_constructible_v<accessor_type>
+ constexpr explicit(_Nm != rank_dynamic())
+ mdspan(data_handle_type __handle, span<_OIndexType, _Nm> __exts)
+ : _M_accessor(), _M_mapping(extents_type(__exts)),
+ _M_handle(std::move(__handle))
+ { }
+
+ template<typename _OIndexType, size_t _Nm>
+ requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
+ && (_Nm == rank() || _Nm == rank_dynamic())
+ && is_constructible_v<mapping_type, extents_type>
+ && is_default_constructible_v<accessor_type>
+ constexpr explicit(_Nm != rank_dynamic())
+ mdspan(data_handle_type __handle, const array<_OIndexType, _Nm>& __exts)
+ : _M_accessor(), _M_mapping(extents_type(__exts)),
+ _M_handle(std::move(__handle))
+ { }
+
+ constexpr
+ mdspan(data_handle_type __handle, const extents_type& __exts)
+ requires is_constructible_v<mapping_type, const extents_type&>
+ && is_default_constructible_v<accessor_type>
+ : _M_accessor(), _M_mapping(__exts), _M_handle(std::move(__handle))
+ { }
+
+ constexpr
+ mdspan(data_handle_type __handle, const mapping_type& __mapping)
+ requires is_default_constructible_v<accessor_type>
+ : _M_accessor(), _M_mapping(__mapping), _M_handle(std::move(__handle))
+ { }
+
+ constexpr
+ mdspan(data_handle_type __handle, const mapping_type& __mapping,
+ const accessor_type& __accessor)
+ : _M_accessor(__accessor), _M_mapping(__mapping),
+ _M_handle(std::move(__handle))
+ { }
+
+ template<typename _OElementType, typename _OExtents, typename _OLayout,
+ typename _OAccessor>
+ requires is_constructible_v<mapping_type,
+ const typename _OLayout::template mapping<_OExtents>&>
+ && is_constructible_v<accessor_type, const _OAccessor&>
+ constexpr explicit(!is_convertible_v<
+ const typename _OLayout::template mapping<_OExtents>&, mapping_type>
+ || !is_convertible_v<const _OAccessor&, accessor_type>)
+ mdspan(const mdspan<_OElementType, _OExtents, _OLayout, _OAccessor>&
+ __other)
+ : _M_accessor(__other.accessor()), _M_mapping(__other.mapping()),
+ _M_handle(__other.data_handle())
+ {
+ static_assert(is_constructible_v<data_handle_type,
+ const typename _OAccessor::data_handle_type&>);
+ static_assert(is_constructible_v<extents_type, _OExtents>);
+ }
+
+ constexpr mdspan&
+ operator=(const mdspan& __other) = default;
+
+ constexpr mdspan&
+ operator=(mdspan&& __other) = default;
+
+ template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
+ requires (sizeof...(_OIndexTypes) == rank())
+ constexpr reference
+ operator[](_OIndexTypes... __indices) const
+ {
+ auto __checked_call = [this](auto... __idxs) -> index_type
+ {
+ if constexpr (sizeof...(__idxs) > 0)
+ __glibcxx_assert(__mdspan::__is_multi_index(extents(),
+ span<const index_type, sizeof...(__idxs)>({__idxs...})));
+ return _M_mapping(__idxs...);
+ };
+
+ auto __index = __checked_call(
+ static_cast<index_type>(std::move(__indices))...);
+ return _M_accessor.access(_M_handle, __index);
+ }
+
+ template<typename _OIndexType>
+ requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
+ constexpr reference
+ operator[](span<_OIndexType, rank()> __indices) const
+ {
+ auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>)
+ -> reference
+ { return (*this)[index_type(as_const(__indices[_Counts]))...]; };
+ return __call(make_index_sequence<rank()>());
+ }
+
+ template<typename _OIndexType>
+ requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
+ constexpr reference
+ operator[](const array<_OIndexType, rank()>& __indices) const
+ { return (*this)[span<const _OIndexType, rank()>(__indices)]; }
+
+ constexpr size_type
+ size() const noexcept
+ {
+ __glibcxx_assert(cmp_less_equal(_M_mapping.required_span_size(),
+ __gnu_cxx::__int_traits<size_t>
+ ::__max));
+ return size_type(__mdspan::__size(extents()));
+ }
+
+ [[nodiscard]]
+ constexpr bool
+ empty() const noexcept
+ { return __mdspan::__empty(extents()); }
+
+ friend constexpr void
+ swap(mdspan& __x, mdspan& __y) noexcept
+ {
+ using std::swap;
+ swap(__x._M_mapping, __y._M_mapping);
+ swap(__x._M_accessor, __y._M_accessor);
+ swap(__x._M_handle, __y._M_handle);
+ }
+
+ constexpr const extents_type&
+ extents() const noexcept { return _M_mapping.extents(); }
+
+ constexpr const data_handle_type&
+ data_handle() const noexcept { return _M_handle; }
+
+ constexpr const mapping_type&
+ mapping() const noexcept { return _M_mapping; }
+
+ constexpr const accessor_type&
+ accessor() const noexcept { return _M_accessor; }
+
+ // Strengthened noexcept for all `is_*` methods.
+
+ static constexpr bool
+ is_always_unique() noexcept(noexcept(mapping_type::is_always_unique()))
+ { return mapping_type::is_always_unique(); }
+
+ static constexpr bool
+ is_always_exhaustive()
+ noexcept(noexcept(mapping_type::is_always_exhaustive()))
+ { return mapping_type::is_always_exhaustive(); }
+
+ static constexpr bool
+ is_always_strided()
+ noexcept(noexcept(mapping_type::is_always_strided()))
+ { return mapping_type::is_always_strided(); }
+
+ constexpr bool
+ is_unique() const noexcept(noexcept(_M_mapping.is_unique()))
+ { return _M_mapping.is_unique(); }
+
+ constexpr bool
+ is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive()))
+ { return _M_mapping.is_exhaustive(); }
+
+ constexpr bool
+ is_strided() const noexcept(noexcept(_M_mapping.is_strided()))
+ { return _M_mapping.is_strided(); }
+
+ constexpr index_type
+ stride(rank_type __r) const { return _M_mapping.stride(__r); }
+
+ private:
+ [[no_unique_address]] accessor_type _M_accessor = accessor_type();
+ [[no_unique_address]] mapping_type _M_mapping = mapping_type();
+ [[no_unique_address]] data_handle_type _M_handle = data_handle_type();
+ };
+
+ template<typename _CArray>
+ requires is_array_v<_CArray> && (rank_v<_CArray> == 1)
+ mdspan(_CArray&)
+ -> mdspan<remove_all_extents_t<_CArray>,
+ extents<size_t, extent_v<_CArray, 0>>>;
+
+ template<typename _Pointer>
+ requires is_pointer_v<remove_reference_t<_Pointer>>
+ mdspan(_Pointer&&)
+ -> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>;
+
+ template<typename _ElementType, typename... _Integrals>
+ requires (is_convertible_v<_Integrals, size_t> && ...)
+ && (sizeof...(_Integrals) > 0)
+ explicit mdspan(_ElementType*, _Integrals...)
+ -> mdspan<_ElementType,
+ extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>;
+
+ template<typename _ElementType, typename _OIndexType, size_t _Nm>
+ mdspan(_ElementType*, span<_OIndexType, _Nm>)
+ -> mdspan<_ElementType, dextents<size_t, _Nm>>;
+
+ template<typename _ElementType, typename _OIndexType, size_t _Nm>
+ mdspan(_ElementType*, const array<_OIndexType, _Nm>&)
+ -> mdspan<_ElementType, dextents<size_t, _Nm>>;
+
+ template<typename _ElementType, typename _IndexType, size_t... _ExtentsPack>
+ mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&)
+ -> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>;
+
+ template<typename _ElementType, typename _MappingType>
+ mdspan(_ElementType*, const _MappingType&)
+ -> mdspan<_ElementType, typename _MappingType::extents_type,
+ typename _MappingType::layout_type>;
+
+ template<typename _MappingType, typename _AccessorType>
+ mdspan(const typename _AccessorType::data_handle_type&, const _MappingType&,
+ const _AccessorType&)
+ -> mdspan<typename _AccessorType::element_type,
+ typename _MappingType::extents_type,
+ typename _MappingType::layout_type, _AccessorType>;
+
+#if __glibcxx_submdspan
+ namespace __mdspan
+ {
+ template<typename _IndexType, typename _Slice>
+ constexpr auto
+ __canonical_index(_Slice&& __slice)
+ {
+ if constexpr (__detail::__integral_constant_like<_Slice>)
+ {
+ static_assert(__is_representable_integer<_IndexType>(_Slice::value));
+ static_assert(_Slice::value >= 0);
+ return std::cw<_IndexType(_Slice::value)>;
+ }
+ else
+ return __mdspan::__index_type_cast<_IndexType>(std::move(__slice));
+ }
+
+ template<typename _IndexType, typename _Slice>
+ constexpr auto
+ __slice_cast(_Slice&& __slice)
+ {
+ using _SliceType = remove_cvref_t<_Slice>;
+ if constexpr (is_convertible_v<_SliceType, full_extent_t>)
+ return static_cast<full_extent_t>(std::move(__slice));
+ else if constexpr (is_convertible_v<_SliceType, _IndexType>)
+ return __mdspan::__canonical_index<_IndexType>(std::move(__slice));
+ else if constexpr (__is_strided_slice<_SliceType>)
+ {
+ auto __extent
+ = __mdspan::__canonical_index<_IndexType>(std::move(__slice.extent));
+ auto __offset
+ = __mdspan::__canonical_index<_IndexType>(std::move(__slice.offset));
+ if constexpr (is_same_v<decltype(__extent),
+ constant_wrapper<_IndexType(0)>>)
+ return strided_slice{
+ .offset = __offset,
+ .extent = __extent,
+ .stride = cw<_IndexType(1)>
+ };
+ else
+ return strided_slice{
+ .offset = __offset,
+ .extent = __extent,
+ .stride
+ = __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride))
+ };
+ }
+ else
+ {
+ auto [__sbegin, __send] = std::move(__slice);
+ auto __offset
+ = __mdspan::__canonical_index<_IndexType>(std::move(__sbegin));
+ auto __end
+ = __mdspan::__canonical_index<_IndexType>(std::move(__send));
+ return strided_slice{
+ .offset = __offset,
+ .extent = __mdspan::__canonical_index<_IndexType>(__end - __offset),
+ .stride = cw<_IndexType(1)>
+ };
+ }
+ }
+
+ template<typename _IndexType, size_t _Extent, typename _OIndexType>
+ constexpr void
+ __check_valid_index(const extents<_IndexType, _Extent>& __ext,
+ const _OIndexType& __idx)
+ {
+ if constexpr (__is_constant_wrapper<_OIndexType>
+ && _Extent != dynamic_extent)
+ {
+ static_assert(_OIndexType::value >= 0);
+ static_assert(std::cmp_less_equal(_OIndexType::value, _Extent));
+ }
+ else
+ __glibcxx_assert(__idx <= __ext.extent(0));
+}
+
+ template<typename _IndexType, size_t _Extent, typename _Slice>
+ constexpr void
+ __check_valid_slice(const extents<_IndexType, _Extent>& __ext,
+ const _Slice& __slice)
+ {
+ if constexpr (__is_strided_slice<_Slice>)
+ {
+ // DEVIATION: For empty slices, P3663r3 does not allow us to check
+ // that this is less than or equal to the k-th extent (at runtime).
+ // We're only allowed to check if __slice.offset, __slice.extent
+ // are constant wrappers and __ext is a static extent.
+ __mdspan::__check_valid_index(__ext, __slice.offset);
+ __mdspan::__check_valid_index(__ext, __slice.extent);
+
+ if constexpr (__is_constant_wrapper<typename _Slice::extent_type>
+ && __is_constant_wrapper<typename _Slice::stride_type>)
+ static_assert(_Slice::stride_type::value > 0);
+ else
+ __glibcxx_assert(__slice.extent == 0 || __slice.stride > 0);
+
+ if constexpr (__is_constant_wrapper<typename _Slice::offset_type>
+ && __is_constant_wrapper<typename _Slice::extent_type>
+ && _Extent != dynamic_extent)
+ static_assert(std::cmp_greater_equal(
+ _Extent - _Slice::offset_type::value,
+ _Slice::extent_type::value));
+ else
+ __glibcxx_assert(__ext.extent(0) - __slice.offset
+ >= __slice.extent);
+ }
+ else if constexpr (__is_constant_wrapper<_Slice>
+ && _Extent != dynamic_extent)
+ static_assert(std::cmp_less(_Slice::value, _Extent));
+ else if constexpr (convertible_to<_Slice, _IndexType>)
+ __glibcxx_assert(__slice < __ext.extent(0));
+ }
+
+ template<typename _Extents, typename... _Slices>
+ constexpr void
+ __check_valid_slices(const _Extents& __exts, const _Slices&... __slices)
+ {
+ constexpr auto __rank = _Extents::rank();
+ auto __impl = [&]<size_t... _Is>(index_sequence<_Is...>)
+ {
+ ((__mdspan::__check_valid_slice(__extract_extent<_Is>(__exts),
+ __slices...[_Is])),...);
+ };
+ __impl(make_index_sequence<__rank>());
+ }
+
+ template<typename _Slice>
+ using __full_extent_t = std::full_extent_t;
+
+ // Enables ADL-only calls from submdspan.
+ void submdspan_mapping() = delete;
+
+ template<typename _Mapping, typename... _Slices>
+ concept __sliceable_mapping = requires(const _Mapping __m, _Slices... __slices)
+ {
+ { submdspan_mapping(__m, __slices...) } -> __submdspan_mapping_result;
+ };
+
+ template<typename _Mapping, typename... _Slices>
+ constexpr auto
+ __submapping(const _Mapping& __mapping, _Slices... __slices)
+ {
+ __mdspan::__check_valid_slices(__mapping.extents(), __slices...);
+ return submdspan_mapping(__mapping, __slices...);
+ }
+ }
+
+ template<typename _IndexType, size_t... _Extents, typename... _RawSlices>
+ requires (sizeof...(_RawSlices) == sizeof...(_Extents))
+ constexpr auto
+ submdspan_extents(const extents<_IndexType, _Extents...>& __exts,
+ _RawSlices... __raw_slices)
+ {
+ auto __impl = [&__exts](auto... __slices)
+ {
+ __mdspan::__check_valid_slices(__exts, __slices...);
+ return __mdspan::__subextents(__exts, __slices...);
+ };
+ return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...);
+ }
+
+ template<typename _IndexType, size_t... _Extents, typename... _RawSlices>
+ requires (sizeof...(_Extents) == sizeof...(_RawSlices))
+ constexpr auto
+ submdspan_canonicalize_slices(const extents<_IndexType, _Extents...>& __exts,
+ _RawSlices... __raw_slices)
+ {
+ auto __impl = [&__exts](auto... __slices)
+ {
+ __mdspan::__check_valid_slices(__exts, __slices...);
+ return std::make_tuple(__slices...);
+ };
+ return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...);
+ }
+
+ template<typename _ElementType, typename _Extents, typename _Layout,
+ typename _Accessor, typename... _RawSlices>
+ requires (sizeof...(_RawSlices) == _Extents::rank()
+ && __mdspan::__sliceable_mapping<typename _Layout::mapping<_Extents>,
+ __mdspan::__full_extent_t<_RawSlices>...>)
+ constexpr auto
+ submdspan(
+ const mdspan<_ElementType, _Extents, _Layout, _Accessor>& __md,
+ _RawSlices... __raw_slices)
+ {
+ using _IndexType = typename _Extents::index_type;
+ auto [__mapping, __offset] = __mdspan::__submapping(
+ __md.mapping(), __mdspan::__slice_cast<_IndexType>(__raw_slices)...);
+ return std::mdspan(
+ __md.accessor().offset(__md.data_handle(), __offset),
+ std::move(__mapping),
+ typename _Accessor::offset_policy(__md.accessor()));
+ }
+#endif // __glibcxx_submdspan
+
+_GLIBCXX_END_NAMESPACE_VERSION
+}
+#endif
+#endif
diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory
index 99f542d..9763760 100644
--- a/libstdc++-v3/include/std/memory
+++ b/libstdc++-v3/include/std/memory
@@ -97,6 +97,11 @@
# include <bits/out_ptr.h>
#endif
+#if __cplusplus > 202302L
+# include <bits/indirect.h>
+#endif
+
+#define __glibcxx_want_addressof_constexpr
#define __glibcxx_want_allocator_traits_is_always_equal
#define __glibcxx_want_assume_aligned
#define __glibcxx_want_atomic_shared_ptr
@@ -104,16 +109,21 @@
#define __glibcxx_want_constexpr_dynamic_alloc
#define __glibcxx_want_constexpr_memory
#define __glibcxx_want_enable_shared_from_this
+#define __glibcxx_want_indirect
+#define __glibcxx_want_is_sufficiently_aligned
#define __glibcxx_want_make_unique
#define __glibcxx_want_out_ptr
#define __glibcxx_want_parallel_algorithm
+#define __glibcxx_want_polymorphic
#define __glibcxx_want_ranges
#define __glibcxx_want_raw_memory_algorithms
#define __glibcxx_want_shared_ptr_arrays
#define __glibcxx_want_shared_ptr_weak_type
#define __glibcxx_want_smart_ptr_for_overwrite
+#define __glibcxx_want_start_lifetime_as
#define __glibcxx_want_to_address
#define __glibcxx_want_transparent_operators
+#define __glibcxx_want_smart_ptr_owner_equality
#include <bits/version.h>
#if __cplusplus >= 201103L && __cplusplus <= 202002L && _GLIBCXX_HOSTED
diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex
index b3f89c0..d4fc4c6 100644
--- a/libstdc++-v3/include/std/mutex
+++ b/libstdc++-v3/include/std/mutex
@@ -179,31 +179,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_try_lock_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts = {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
return static_cast<_Derived*>(this)->_M_timedlock(__ts);
}
-#ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
+#if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
template<typename _Duration>
bool
_M_try_lock_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts = {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime);
return static_cast<_Derived*>(this)->_M_clocklock(CLOCK_MONOTONIC,
__ts);
}
@@ -377,7 +363,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_timedlock(const __gthread_time_t& __ts)
{ return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); }
-#ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
+#if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK
bool
_M_clocklock(clockid_t __clockid, const __gthread_time_t& __ts)
{ return !pthread_mutex_clocklock(&_M_mutex, __clockid, &__ts); }
@@ -733,7 +719,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
}
-#ifdef __cpp_lib_scoped_lock // C++ >= 17 && hosted && gthread
+#ifdef __cpp_lib_scoped_lock // C++ >= 17
/** @brief A scoped lock type for multiple lockable objects.
*
* A scoped_lock controls mutex ownership within a scope, releasing
diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index 490963e..cbabf031 100644
--- a/libstdc++-v3/include/std/numeric
+++ b/libstdc++-v3/include/std/numeric
@@ -582,7 +582,7 @@ namespace __detail
{
if (__first != __last)
{
- auto __init = *__first;
+ auto __init = std::move(*__first);
*__result++ = __init;
++__first;
if (__first != __last)
@@ -645,8 +645,8 @@ namespace __detail
{
while (__first != __last)
{
- auto __v = __init;
- __init = __binary_op(__init, __unary_op(*__first));
+ auto __v = std::move(__init);
+ __init = __binary_op(__v, __unary_op(*__first));
++__first;
*__result++ = std::move(__v);
}
diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional
index a616dc0..8b9fa92 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -36,6 +36,7 @@
#define __glibcxx_want_freestanding_optional
#define __glibcxx_want_optional
+#define __glibcxx_want_optional_range_support
#define __glibcxx_want_constrained_equality
#include <bits/version.h>
@@ -57,6 +58,11 @@
#if __cplusplus > 202002L
# include <concepts>
#endif
+#ifdef __cpp_lib_optional_range_support // C++ >= 26
+# include <bits/formatfwd.h>
+# include <bits/ranges_base.h>
+# include <bits/stl_iterator.h>
+#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -771,6 +777,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
# define _GLIBCXX_USE_CONSTRAINTS_FOR_OPTIONAL 1
#endif
+ template<typename _Tp>
+ inline constexpr bool __is_valid_contained_type_for_optional =
+ (
+#if __cpp_lib_optional >= 202506L
+ is_lvalue_reference_v<_Tp> ||
+#endif
+ (is_object_v<_Tp> && is_destructible_v<_Tp> && !is_array_v<_Tp>)
+ )
+ && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, nullopt_t>
+ && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, in_place_t>;
+
/**
* @brief Class template for optional values.
*/
@@ -789,9 +806,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Unique tag type.
optional<_Tp>>
{
- static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>);
- static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>);
- static_assert(is_object_v<_Tp> && !is_array_v<_Tp>);
+ static_assert(__is_valid_contained_type_for_optional<_Tp>);
private:
using _Base = _Optional_base<_Tp>;
@@ -858,6 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
public:
using value_type = _Tp;
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional>;
+ using const_iterator = __gnu_cxx::__normal_iterator<const _Tp*, optional>;
+#endif
constexpr optional() noexcept { }
@@ -884,7 +903,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(is_nothrow_constructible_v<_Tp, const _Up&>)
{
if (__t)
- emplace(__t._M_get());
+ emplace(__t._M_fwd());
}
template<typename _Up>
@@ -896,7 +915,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(is_nothrow_constructible_v<_Tp, _Up>)
{
if (__t)
- emplace(std::move(__t._M_get()));
+ emplace(std::move(__t)._M_fwd());
}
template<typename... _Args>
@@ -946,7 +965,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(is_nothrow_constructible_v<_Tp, const _Up&>)
{
if (__t)
- emplace(__t._M_get());
+ emplace(__t._M_fwd());
}
template<typename _Up,
@@ -959,7 +978,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(is_nothrow_constructible_v<_Tp, const _Up&>)
{
if (__t)
- emplace(__t._M_get());
+ emplace(__t._M_fwd());
}
template<typename _Up,
@@ -972,7 +991,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(is_nothrow_constructible_v<_Tp, _Up>)
{
if (__t)
- emplace(std::move(__t._M_get()));
+ emplace(std::move(__t)._M_fwd());
}
template<typename _Up,
@@ -985,7 +1004,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(is_nothrow_constructible_v<_Tp, _Up>)
{
if (__t)
- emplace(std::move(__t._M_get()));
+ emplace(std::move(__t)._M_fwd());
}
template<typename... _Args,
@@ -1064,9 +1083,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__u)
{
if (this->_M_is_engaged())
- this->_M_get() = __u._M_get();
+ this->_M_get() = __u._M_fwd();
else
- this->_M_construct(__u._M_get());
+ this->_M_construct(__u._M_fwd());
}
else
{
@@ -1098,9 +1117,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__u)
{
if (this->_M_is_engaged())
- this->_M_get() = std::move(__u._M_get());
+ this->_M_get() = std::move(__u)._M_fwd();
else
- this->_M_construct(std::move(__u._M_get()));
+ this->_M_construct(std::move(__u)._M_fwd());
}
else
{
@@ -1158,6 +1177,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
}
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ // Iterator support.
+ constexpr iterator begin() noexcept
+ {
+ return iterator(
+ this->_M_is_engaged() ? std::addressof(this->_M_get()) : nullptr
+ );
+ }
+
+ constexpr const_iterator begin() const noexcept
+ {
+ return const_iterator(
+ this->_M_is_engaged() ? std::addressof(this->_M_get()) : nullptr
+ );
+ }
+
+ constexpr iterator end() noexcept
+ {
+ return begin() + has_value();
+ }
+
+ constexpr const_iterator end() const noexcept
+ {
+ return begin() + has_value();
+ }
+#endif // __cpp_lib_optional_range_support
+
// Observers.
constexpr const _Tp*
operator->() const noexcept
@@ -1239,30 +1285,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__throw_bad_optional_access();
}
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4406. value_or return statement is inconsistent with Mandates
template<typename _Up = remove_cv_t<_Tp>>
- constexpr _Tp
+ constexpr remove_cv_t<_Tp>
value_or(_Up&& __u) const&
{
- static_assert(is_copy_constructible_v<_Tp>);
- static_assert(is_convertible_v<_Up&&, _Tp>);
+ using _Xp = remove_cv_t<_Tp>;
+ static_assert(is_convertible_v<const _Tp&, _Xp>);
+ static_assert(is_convertible_v<_Up, _Xp>);
if (this->_M_is_engaged())
return this->_M_get();
- else
- return static_cast<_Tp>(std::forward<_Up>(__u));
+ return std::forward<_Up>(__u);
}
template<typename _Up = remove_cv_t<_Tp>>
- constexpr _Tp
+ constexpr remove_cv_t<_Tp>
value_or(_Up&& __u) &&
{
- static_assert(is_move_constructible_v<_Tp>);
- static_assert(is_convertible_v<_Up&&, _Tp>);
+ using _Xp = remove_cv_t<_Tp>;
+ static_assert(is_convertible_v<_Tp, _Xp>);
+ static_assert(is_convertible_v<_Up, _Xp>);
if (this->_M_is_engaged())
return std::move(this->_M_get());
- else
- return static_cast<_Tp>(std::forward<_Up>(__u));
+ return std::forward<_Up>(__u);
}
#if __cpp_lib_optional >= 202110L // C++23
@@ -1273,7 +1321,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
and_then(_Fn&& __f) &
{
using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp&>>;
- static_assert(__is_optional_v<remove_cvref_t<_Up>>,
+ static_assert(__is_optional_v<_Up>,
"the function passed to std::optional<T>::and_then "
"must return a std::optional");
if (has_value())
@@ -1301,7 +1349,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
and_then(_Fn&& __f) &&
{
using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp>>;
- static_assert(__is_optional_v<remove_cvref_t<_Up>>,
+ static_assert(__is_optional_v<_Up>,
"the function passed to std::optional<T>::and_then "
"must return a std::optional");
if (has_value())
@@ -1315,7 +1363,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
and_then(_Fn&& __f) const &&
{
using _Up = remove_cvref_t<invoke_result_t<_Fn, const _Tp>>;
- static_assert(__is_optional_v<remove_cvref_t<_Up>>,
+ static_assert(__is_optional_v<_Up>,
"the function passed to std::optional<T>::and_then "
"must return a std::optional");
if (has_value())
@@ -1404,6 +1452,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
private:
using _Base::_M_get;
+ [[__gnu__::__always_inline__]]
+ constexpr _Tp&
+ _M_fwd() & noexcept
+ { return _M_get(); }
+
+ [[__gnu__::__always_inline__]]
+ constexpr _Tp&&
+ _M_fwd() && noexcept
+ { return std::move(_M_get()); }
+
+ [[__gnu__::__always_inline__]]
+ constexpr const _Tp&
+ _M_fwd() const& noexcept
+ { return _M_get(); }
+
+ [[__gnu__::__always_inline__]]
+ constexpr const _Tp&&
+ _M_fwd() const&& noexcept
+ { return std::move(_M_get()); }
+
template<typename _Up> friend class optional;
#if __cpp_lib_optional >= 202110L // C++23
@@ -1416,6 +1484,337 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
};
+#if __cpp_lib_optional >= 202506L // C++26
+ template<typename _Tp>
+ class optional<_Tp&>;
+
+ template<typename _Tp>
+ constexpr bool __is_optional_ref_v = false;
+
+ template<typename _Tp>
+ constexpr bool __is_optional_ref_v<optional<_Tp&>> = true;
+
+ template<typename _Tp>
+ struct __optional_ref_base
+ {};
+
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ template<typename _Tp>
+ struct __optional_ref_base<_Tp[]>
+ {};
+
+ template<typename _Tp>
+ requires is_object_v<_Tp>
+ struct __optional_ref_base<_Tp>
+ {
+ using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional<_Tp&>>;
+ };
+#endif // __cpp_lib_optional_range_support
+
+ template<typename _Tp>
+ class optional<_Tp&> : public __optional_ref_base<_Tp>
+ {
+ static_assert(__is_valid_contained_type_for_optional<_Tp&>);
+
+ public:
+ using value_type = _Tp;
+
+ // Constructors.
+ constexpr optional() noexcept = default;
+ constexpr optional(nullopt_t) noexcept : optional() {}
+ constexpr optional(const optional&) noexcept = default;
+
+ template<typename _Arg>
+ requires is_constructible_v<_Tp&, _Arg>
+ && (!reference_constructs_from_temporary_v<_Tp&, _Arg>)
+ explicit constexpr
+ optional(in_place_t, _Arg&& __arg)
+ {
+ __convert_ref_init_val(std::forward<_Arg>(__arg));
+ }
+
+ template<typename _Up>
+ requires (!is_same_v<remove_cvref_t<_Up>, optional>)
+ && (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
+ && is_constructible_v<_Tp&, _Up>
+ && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
+ explicit(!is_convertible_v<_Up, _Tp&>)
+ constexpr
+ optional(_Up&& __u)
+ noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
+ {
+ __convert_ref_init_val(std::forward<_Up>(__u));
+ }
+
+ template<typename _Up>
+ requires (!is_same_v<remove_cvref_t<_Up>, optional>)
+ && (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
+ && is_constructible_v<_Tp&, _Up>
+ && reference_constructs_from_temporary_v<_Tp&, _Up>
+ explicit(!is_convertible_v<_Up, _Tp&>)
+ constexpr
+ optional(_Up&& __u) = delete;
+
+ // optional<U> &
+ template<typename _Up>
+ requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
+ && (!is_same_v<_Tp&, _Up>)
+ && is_constructible_v<_Tp&, _Up&>
+ && (!reference_constructs_from_temporary_v<_Tp&, _Up&>)
+ explicit(!is_convertible_v<_Up&, _Tp&>)
+ constexpr
+ optional(optional<_Up>& __rhs)
+ noexcept(is_nothrow_constructible_v<_Tp&, _Up&>)
+ {
+ if (__rhs)
+ __convert_ref_init_val(__rhs._M_fwd());
+ }
+
+ template<typename _Up>
+ requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
+ && (!is_same_v<_Tp&, _Up>)
+ && is_constructible_v<_Tp&, _Up&>
+ && reference_constructs_from_temporary_v<_Tp&, _Up&>
+ explicit(!is_convertible_v<_Up&, _Tp&>)
+ constexpr
+ optional(optional<_Up>& __rhs) = delete;
+
+ // const optional<U>&
+ template<typename _Up>
+ requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
+ && (!is_same_v<_Tp&, _Up>)
+ && is_constructible_v<_Tp&, const _Up&>
+ && (!reference_constructs_from_temporary_v<_Tp&, const _Up&>)
+ explicit(!is_convertible_v<const _Up&, _Tp&>)
+ constexpr
+ optional(const optional<_Up>& __rhs)
+ noexcept(is_nothrow_constructible_v<_Tp&, _Up&>)
+ {
+ if (__rhs)
+ __convert_ref_init_val(__rhs._M_fwd());
+ }
+
+ template<typename _Up>
+ requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
+ && (!is_same_v<_Tp&, _Up>)
+ && is_constructible_v<_Tp&, const _Up&>
+ && reference_constructs_from_temporary_v<_Tp&, const _Up&>
+ explicit(!is_convertible_v<const _Up&, _Tp&>)
+ constexpr
+ optional(const optional<_Up>& __rhs) = delete;
+
+ // optional<U>&&
+ template<typename _Up>
+ requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
+ && (!is_same_v<_Tp&, _Up>)
+ && is_constructible_v<_Tp&, _Up>
+ && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
+ explicit(!is_convertible_v<_Up, _Tp&>)
+ constexpr
+ optional(optional<_Up>&& __rhs)
+ noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
+ {
+ if (__rhs)
+ __convert_ref_init_val(std::move(__rhs)._M_fwd());
+ }
+
+ template<typename _Up>
+ requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
+ && (!is_same_v<_Tp&, _Up>)
+ && is_constructible_v<_Tp&, _Up>
+ && reference_constructs_from_temporary_v<_Tp&, _Up>
+ explicit(!is_convertible_v<_Up, _Tp&>)
+ constexpr
+ optional(optional<_Up>&& __rhs) = delete;
+
+ // const optional<U>&&
+ template<typename _Up>
+ requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
+ && (!is_same_v<_Tp&, _Up>)
+ && is_constructible_v<_Tp&, const _Up>
+ && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
+ explicit(!is_convertible_v<const _Up, _Tp&>)
+ constexpr
+ optional(const optional<_Up>&& __rhs)
+ noexcept(is_nothrow_constructible_v<_Tp&, const _Up>)
+ {
+ if (__rhs)
+ __convert_ref_init_val(std::move(__rhs)._M_fwd());
+ }
+
+ template<typename _Up>
+ requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
+ && (!is_same_v<_Tp&, _Up>)
+ && is_constructible_v<_Tp&, const _Up>
+ && reference_constructs_from_temporary_v<_Tp&, const _Up>
+ explicit(!is_convertible_v<const _Up, _Tp&>)
+ constexpr
+ optional(const optional<_Up>&& __rhs) = delete;
+
+ constexpr ~optional() = default;
+
+ // Assignment.
+ constexpr optional& operator=(nullopt_t) noexcept
+ {
+ _M_val = nullptr;
+ return *this;
+ }
+
+ constexpr optional& operator=(const optional&) noexcept = default;
+
+ template<typename _Up>
+ requires is_constructible_v<_Tp&, _Up>
+ && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
+ constexpr _Tp&
+ emplace(_Up&& __u)
+ noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
+ {
+ __convert_ref_init_val(std::forward<_Up>(__u));
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4300. Missing Returns: element in optional<T&>::emplace
+ return *_M_val;
+ }
+
+ // Swap.
+ constexpr void swap(optional& __rhs) noexcept
+ { std::swap(_M_val, __rhs._M_val); }
+
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ // Iterator support.
+ constexpr auto begin() const noexcept
+ requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>)
+ { return __gnu_cxx::__normal_iterator<_Tp*, optional>(_M_val); }
+
+ constexpr auto end() const noexcept
+ requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>)
+ { return begin() + has_value(); }
+#endif // __cpp_lib_optional_range_support
+
+ // Observers.
+ constexpr _Tp* operator->() const noexcept
+ {
+ __glibcxx_assert(_M_val); // hardened precondition
+ return _M_val;
+ }
+
+ constexpr _Tp& operator*() const noexcept
+ {
+ __glibcxx_assert(_M_val); // hardened precondition
+ return *_M_val;
+ }
+
+ constexpr explicit operator bool() const noexcept
+ {
+ return _M_val;
+ }
+
+ constexpr bool has_value() const noexcept
+ {
+ return _M_val;
+ }
+
+ constexpr _Tp& value() const
+ {
+ if (_M_val)
+ return *_M_val;
+ __throw_bad_optional_access();
+ }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4304. std::optional<NonReturnable&> is ill-formed due to value_or
+ template<typename _Up = remove_cv_t<_Tp>>
+ requires is_object_v<_Tp> && (!is_array_v<_Tp>)
+ constexpr decay_t<_Tp>
+ value_or(_Up&& __u) const
+ {
+ using _Xp = remove_cv_t<_Tp>;
+ static_assert(is_convertible_v<_Tp&, _Xp>);
+ static_assert(is_convertible_v<_Up, _Xp>);
+ if (_M_val)
+ return *_M_val;
+ return std::forward<_Up>(__u);
+ }
+
+ // Monadic operations.
+ template<typename _Fn>
+ constexpr auto
+ and_then(_Fn&& __f) const
+ {
+ using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp&>>;
+ static_assert(__is_optional_v<_Up>,
+ "the function passed to std::optional<T&>::and_then "
+ "must return a std::optional");
+ if (has_value())
+ return std::__invoke(std::forward<_Fn>(__f), *_M_val);
+ else
+ return _Up();
+ }
+
+ template<typename _Fn>
+ constexpr
+ optional<remove_cv_t<invoke_result_t<_Fn, _Tp&>>>
+ transform(_Fn&& __f) const
+ {
+ using _Up = remove_cv_t<invoke_result_t<_Fn, _Tp&>>;
+ if (has_value())
+ return optional<_Up>(_Optional_func<_Fn>{__f}, *_M_val);
+ else
+ return optional<_Up>();
+ }
+
+ template<typename _Fn>
+ requires invocable<_Fn>
+ constexpr
+ optional
+ or_else(_Fn&& __f) const
+ {
+ static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Fn>>, optional>,
+ "the function passed to std::optional<T&>::or_else "
+ "must return a std::optional<T&>");
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4367. Improve optional<T&>::or_else
+ if (has_value())
+ return *this;
+ else
+ return std::forward<_Fn>(__f)();
+ }
+
+ // Modifiers.
+ constexpr void reset() noexcept
+ {
+ _M_val = nullptr;
+ }
+
+ private:
+ _Tp *_M_val = nullptr;
+
+ [[__gnu__::__always_inline__]]
+ constexpr _Tp&
+ _M_fwd() const noexcept
+ { return *_M_val; }
+
+ template<typename _Up> friend class optional;
+
+ template<typename _Up>
+ constexpr
+ void
+ __convert_ref_init_val(_Up&& __u)
+ noexcept
+ {
+ _Tp& __r(std::forward<_Up>(__u));
+ _M_val = std::addressof(__r);
+ }
+
+ template<typename _Fn, typename _Value>
+ explicit constexpr
+ optional(_Optional_func<_Fn> __f, _Value&& __v)
+ {
+ _Tp& __r = std::__invoke(std::forward<_Fn>(__f._M_f), std::forward<_Value>(__v));
+ _M_val = std::addressof(__r);
+ }
+ };
+#endif // __cpp_lib_optional >= 202506L
+
template<typename _Tp>
using __optional_relop_t =
enable_if_t<is_convertible_v<_Tp, bool>, bool>;
@@ -1456,8 +1855,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator==(const optional<_Tp>& __lhs, const optional<_Up>& __rhs)
-> __optional_eq_t<_Tp, _Up>
{
- return static_cast<bool>(__lhs) == static_cast<bool>(__rhs)
- && (!__lhs || *__lhs == *__rhs);
+ if (__lhs.has_value() != __rhs.has_value())
+ return false;
+ if (!__lhs.has_value())
+ return true;
+ return *__lhs == *__rhs;
}
template<typename _Tp, typename _Up>
@@ -1465,8 +1867,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator!=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs)
-> __optional_ne_t<_Tp, _Up>
{
- return static_cast<bool>(__lhs) != static_cast<bool>(__rhs)
- || (static_cast<bool>(__lhs) && *__lhs != *__rhs);
+ if (__lhs.has_value() != __rhs.has_value())
+ return true;
+ if (!__lhs.has_value())
+ return false;
+ return *__lhs != *__rhs;
}
template<typename _Tp, typename _Up>
@@ -1474,7 +1879,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator<(const optional<_Tp>& __lhs, const optional<_Up>& __rhs)
-> __optional_lt_t<_Tp, _Up>
{
- return static_cast<bool>(__rhs) && (!__lhs || *__lhs < *__rhs);
+ if (!__rhs.has_value())
+ return false;
+ if (!__lhs.has_value())
+ return true;
+ return *__lhs < *__rhs;
}
template<typename _Tp, typename _Up>
@@ -1482,7 +1891,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator>(const optional<_Tp>& __lhs, const optional<_Up>& __rhs)
-> __optional_gt_t<_Tp, _Up>
{
- return static_cast<bool>(__lhs) && (!__rhs || *__lhs > *__rhs);
+ if (!__lhs.has_value())
+ return false;
+ if (!__rhs.has_value())
+ return true;
+ return *__lhs > *__rhs;
}
template<typename _Tp, typename _Up>
@@ -1490,7 +1903,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator<=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs)
-> __optional_le_t<_Tp, _Up>
{
- return !__lhs || (static_cast<bool>(__rhs) && *__lhs <= *__rhs);
+ if (!__lhs.has_value())
+ return true;
+ if (!__rhs.has_value())
+ return false;
+ return *__lhs <= *__rhs;
}
template<typename _Tp, typename _Up>
@@ -1498,7 +1915,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator>=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs)
-> __optional_ge_t<_Tp, _Up>
{
- return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs);
+ if (!__rhs.has_value())
+ return true;
+ if (!__lhs.has_value())
+ return false;
+ return *__lhs >= *__rhs;
}
#ifdef __cpp_lib_three_way_comparison
@@ -1595,84 +2016,132 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr auto
operator== [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs)
-> __optional_eq_t<_Tp, _Up>
- { return __lhs && *__lhs == __rhs; }
+ {
+ if (__lhs.has_value())
+ return *__lhs == __rhs;
+ return false;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Tp)
constexpr auto
operator== [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs)
-> __optional_eq_t<_Tp, _Up>
- { return __rhs && __lhs == *__rhs; }
+ {
+ if (__rhs.has_value())
+ return __lhs == *__rhs;
+ return false;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Up)
constexpr auto
operator!= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs)
-> __optional_ne_t<_Tp, _Up>
- { return !__lhs || *__lhs != __rhs; }
+ {
+ if (__lhs.has_value())
+ return *__lhs != __rhs;
+ return true;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Tp)
constexpr auto
operator!= [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs)
-> __optional_ne_t<_Tp, _Up>
- { return !__rhs || __lhs != *__rhs; }
+ {
+ if (__rhs.has_value())
+ return __lhs != *__rhs;
+ return true;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Up)
constexpr auto
operator< [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs)
-> __optional_lt_t<_Tp, _Up>
- { return !__lhs || *__lhs < __rhs; }
+ {
+ if (__lhs.has_value())
+ return *__lhs < __rhs;
+ return true;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Tp)
constexpr auto
operator< [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs)
-> __optional_lt_t<_Tp, _Up>
- { return __rhs && __lhs < *__rhs; }
+ {
+ if (__rhs.has_value())
+ return __lhs < *__rhs;
+ return false;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Up)
constexpr auto
operator> [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs)
-> __optional_gt_t<_Tp, _Up>
- { return __lhs && *__lhs > __rhs; }
+ {
+ if (__lhs.has_value())
+ return *__lhs > __rhs;
+ return false;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Tp)
constexpr auto
operator> [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs)
-> __optional_gt_t<_Tp, _Up>
- { return !__rhs || __lhs > *__rhs; }
+ {
+ if (__rhs.has_value())
+ return __lhs > *__rhs;
+ return true;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Up)
constexpr auto
operator<= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs)
-> __optional_le_t<_Tp, _Up>
- { return !__lhs || *__lhs <= __rhs; }
+ {
+ if (__lhs.has_value())
+ return *__lhs <= __rhs;
+ return true;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Tp)
constexpr auto
operator<= [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs)
-> __optional_le_t<_Tp, _Up>
- { return __rhs && __lhs <= *__rhs; }
+ {
+ if (__rhs.has_value())
+ return __lhs <= *__rhs;
+ return false;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Up)
constexpr auto
operator>= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs)
-> __optional_ge_t<_Tp, _Up>
- { return __lhs && *__lhs >= __rhs; }
+ {
+ if (__lhs.has_value())
+ return *__lhs >= __rhs;
+ return false;
+ }
template<typename _Tp, typename _Up>
_REQUIRES_NOT_OPTIONAL(_Tp)
constexpr auto
operator>= [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs)
-> __optional_ge_t<_Tp, _Up>
- { return !__rhs || __lhs >= *__rhs; }
+ {
+ if (__rhs.has_value())
+ return __lhs >= *__rhs;
+ return true;
+ }
#ifdef __cpp_lib_three_way_comparison
// _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -1703,17 +2172,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(noexcept(__lhs.swap(__rhs)))
{ __lhs.swap(__rhs); }
+#if __cpp_lib_optional >= 202506L
+ // We deviate from standard, that do not declared separate swap overload
+ // from optional<T&>.
+ template<typename _Tp>
+ constexpr void
+ swap(optional<_Tp&>& __lhs, optional<_Tp&>& __rhs) noexcept
+ { __lhs.swap(__rhs); }
+#endif
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2766. Swapping non-swappable types
template<typename _Tp>
enable_if_t<!(is_move_constructible_v<_Tp> && is_swappable_v<_Tp>)>
swap(optional<_Tp>&, optional<_Tp>&) = delete;
+#if __cpp_lib_optional >= 202506L
+ template<int = 0, typename _Tp>
+#else
template<typename _Tp>
+#endif
constexpr
enable_if_t<is_constructible_v<decay_t<_Tp>, _Tp>,
optional<decay_t<_Tp>>>
make_optional(_Tp&& __t)
noexcept(is_nothrow_constructible_v<optional<decay_t<_Tp>>, _Tp>)
- { return optional<decay_t<_Tp>>{ std::forward<_Tp>(__t) }; }
+ { return optional<decay_t<_Tp>>( std::forward<_Tp>(__t) ); }
template<typename _Tp, typename... _Args>
constexpr
@@ -1721,7 +2205,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
optional<_Tp>>
make_optional(_Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
- { return optional<_Tp>{ in_place, std::forward<_Args>(__args)... }; }
+ { return optional<_Tp>( in_place, std::forward<_Args>(__args)... ); }
template<typename _Tp, typename _Up, typename... _Args>
constexpr
@@ -1729,7 +2213,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
optional<_Tp>>
make_optional(initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>)
- { return optional<_Tp>{ in_place, __il, std::forward<_Args>(__args)... }; }
+ { return optional<_Tp>( in_place, __il, std::forward<_Args>(__args)... ); }
// Hash.
@@ -1757,6 +2241,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp>
struct hash<optional<_Tp>>
+ // hash for optional<T&> is disabled because is_hash_enabled_for<T&> is false
: public __conditional_t<__is_hash_enabled_for<remove_const_t<_Tp>>,
__optional_hash<_Tp>,
__hash_not_enabled<_Tp>>
@@ -1772,6 +2257,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template <typename _Tp> optional(_Tp) -> optional<_Tp>;
#endif
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ template<typename _Tp>
+ inline constexpr bool
+ ranges::enable_view<optional<_Tp>> = true;
+
+#if __cpp_lib_optional >= 202506L // C++26
+ template<typename _Tp>
+ constexpr bool
+ ranges::enable_borrowed_range<optional<_Tp&>> = true;
+#endif
+
+ template<typename _Tp>
+ inline constexpr range_format
+ format_kind<optional<_Tp>> = range_format::disabled;
+#endif // __cpp_lib_optional_range_support
+
#undef _GLIBCXX_USE_CONSTRAINTS_FOR_OPTIONAL
_GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream
index 644e568..3387296 100644
--- a/libstdc++-v3/include/std/ostream
+++ b/libstdc++-v3/include/std/ostream
@@ -193,7 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
__format::_Str_sink<char> __buf;
std::vformat_to(__buf.out(), __os.getloc(), __fmt, __args);
- auto __out = __buf.view();
+ auto __out = __buf._M_span();
void* __open_terminal(streambuf*);
error_code __write_to_terminal(void*, span<char>);
@@ -259,9 +259,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
print(ostream& __os, format_string<_Args...> __fmt, _Args&&... __args)
{
auto __fmtargs = std::make_format_args(__args...);
+#if defined(_WIN32) && !defined(__CYGWIN__)
if constexpr (__unicode::__literal_encoding_is_utf8())
std::vprint_unicode(__os, __fmt.get(), __fmtargs);
else
+#endif
std::vprint_nonunicode(__os, __fmt.get(), __fmtargs);
}
@@ -269,10 +271,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline void
println(ostream& __os, format_string<_Args...> __fmt, _Args&&... __args)
{
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 4088. println ignores the locale imbued in std::ostream
- std::print(__os, "{}\n", std::format(__os.getloc(), __fmt,
- std::forward<_Args>(__args)...));
+ auto __fmtargs = std::make_format_args(__args...);
+ std::string __fmtn;
+ __fmtn.reserve(__fmt.get().size() + 1);
+ __fmtn = __fmt.get();
+ __fmtn += '\n';
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if constexpr (__unicode::__literal_encoding_is_utf8())
+ std::vprint_unicode(__os, __fmtn, __fmtargs);
+ else
+#endif
+ std::vprint_nonunicode(__os, __fmtn, __fmtargs);
}
// Defined for C++26, supported as an extension to C++23.
diff --git a/libstdc++-v3/include/std/print b/libstdc++-v3/include/std/print
index ea1aaac..6ffd9a4 100644
--- a/libstdc++-v3/include/std/print
+++ b/libstdc++-v3/include/std/print
@@ -53,9 +53,214 @@ namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace __format
+{
+#if _GLIBCXX_USE_STDIO_LOCKING && _GLIBCXX_USE_GLIBC_STDIO_EXT
+ // These are defined in <stdio_ext.h> but we don't want to include that.
+ extern "C" int __fwritable(FILE*) noexcept;
+ extern "C" int __flbf(FILE*) noexcept;
+ extern "C" size_t __fbufsize(FILE*) noexcept;
+
+ // A format sink that writes directly to a Glibc FILE.
+ // The file is locked on construction and its buffer is accessed directly.
+ class _File_sink final : _Buf_sink<char>
+ {
+ struct _File
+ {
+ explicit
+ _File(FILE* __f) : _M_file(__f)
+ {
+ ::flockfile(__f);
+ // Ensure stream is in write mode
+ if (!__fwritable(__f))
+ {
+ ::funlockfile(__f);
+ __throw_system_error(EACCES);
+ }
+ // Allocate buffer if needed:
+ if (_M_write_buf().empty())
+ if (::__overflow(__f, EOF) == EOF)
+ {
+ const int __err = errno;
+ ::funlockfile(__f);
+ __throw_system_error(__err);
+ }
+ }
+
+ ~_File() { ::funlockfile(_M_file); }
+
+ _File(_File&&) = delete;
+
+ // A span viewing the unused portion of the stream's output buffer.
+ std::span<char>
+ _M_write_buf() noexcept
+ {
+ return {_M_file->_IO_write_ptr,
+ size_t(_M_file->_IO_buf_end - _M_file->_IO_write_ptr)};
+ }
+
+ // Flush the output buffer to the file so we can write to it again.
+ void
+ _M_flush()
+ {
+ if (::fflush_unlocked(_M_file))
+ __throw_system_error(errno);
+ }
+
+ // Update the current position in the output buffer.
+ void
+ _M_bump(size_t __n) noexcept
+ { _M_file->_IO_write_ptr += __n; }
+
+ bool
+ _M_line_buffered() const noexcept
+ { return __flbf(_M_file); } // Or: _M_file->_flags & 0x200
+
+ bool
+ _M_unbuffered() const noexcept
+ { return __fbufsize(_M_file) == 1; } // Or: _M_file->_flags & 0x2
+
+ FILE* _M_file;
+ } _M_file;
+
+ bool _M_add_newline; // True for std::println, false for std::print.
+
+ // Flush the stream's put area so it can be refilled.
+ void
+ _M_overflow() override
+ {
+ auto __s = this->_M_used();
+ if (__s.data() == this->_M_buf)
+ {
+ // Characters in internal buffer need to be transferred to the FILE.
+ auto __n = ::fwrite_unlocked(__s.data(), 1, __s.size(),
+ _M_file._M_file);
+ if (__n != __s.size())
+ __throw_system_error(errno);
+ this->_M_reset(this->_M_buf);
+ }
+ else
+ {
+ // Characters were written directly to the FILE's output buffer.
+ _M_file._M_bump(__s.size());
+ _M_file._M_flush();
+ this->_M_reset(_M_file._M_write_buf());
+ }
+ }
+
+ public:
+ _File_sink(FILE* __f, bool __add_newline)
+ : _M_file(__f), _M_add_newline(__add_newline)
+ {
+ if (!_M_file._M_unbuffered())
+ // Write directly to the FILE's output buffer.
+ this->_M_reset(_M_file._M_write_buf());
+ }
+
+ ~_File_sink() noexcept(false)
+ {
+ auto __s = this->_M_used();
+ if (__s.data() == this->_M_buf) // Unbuffered stream
+ {
+ _File_sink::_M_overflow();
+ if (_M_add_newline)
+ ::putc_unlocked('\n', _M_file._M_file);
+ }
+ else
+ {
+ _M_file._M_bump(__s.size());
+ if (_M_add_newline)
+ ::putc_unlocked('\n', _M_file._M_file);
+ else if (_M_file._M_line_buffered() && __s.size()
+ && (__s.back() == '\n'
+ || __builtin_memchr(__s.data(), '\n', __s.size())))
+ _M_file._M_flush();
+ }
+ }
+
+ using _Sink<char>::out;
+ };
+#elif _GLIBCXX_USE_STDIO_LOCKING
+ // A format sink that buffers output and then copies it to a stdio FILE.
+ // The file is locked on construction and written to using fwrite_unlocked.
+ class _File_sink final : _Buf_sink<char>
+ {
+ FILE* _M_file;
+ bool _M_add_newline;
+
+ // Transfer buffer contents to the FILE, so buffer can be refilled.
+ void
+ _M_overflow() override
+ {
+ auto __s = this->_M_used();
+#if _GLIBCXX_HAVE_FWRITE_UNLOCKED
+ auto __n = ::fwrite_unlocked(__s.data(), 1, __s.size(), _M_file);
+ if (__n != __s.size())
+ __throw_system_error(errno);
+#else
+ for (char __c : __s)
+ ::putc_unlocked(__c, _M_file);
+ if (::ferror(_M_file))
+ __throw_system_error(errno);
+#endif
+ this->_M_reset(this->_M_buf);
+ }
+
+ public:
+ _File_sink(FILE* __f, bool __add_newline) noexcept
+ : _Buf_sink<char>(), _M_file(__f), _M_add_newline(__add_newline)
+ { ::flockfile(__f); }
+
+ ~_File_sink() noexcept(false)
+ {
+ _File_sink::_M_overflow();
+ if (_M_add_newline)
+ ::putc_unlocked('\n', _M_file);
+ ::funlockfile(_M_file);
+ }
+
+ using _Sink<char>::out;
+ };
+#else
+ // A wrapper around a format sink that copies the output to a stdio FILE.
+ // This is not actually a _Sink itself, but it creates one to hold the
+ // formatted characters and then copies them to the file when finished.
+ class _File_sink final
+ {
+ FILE* _M_file;
+ _Str_sink<char> _M_sink;
+ bool _M_add_newline;
+
+ public:
+ _File_sink(FILE* __f, bool __add_newline) noexcept
+ : _M_file(__f), _M_add_newline(__add_newline)
+ { }
+
+ ~_File_sink() noexcept(false)
+ {
+ string __s = std::move(_M_sink).get();
+ if (_M_add_newline)
+ __s += '\n';
+ auto __n = std::fwrite(__s.data(), 1, __s.size(), _M_file);
+ if (__n < __s.size())
+ __throw_system_error(EIO);
+ }
+
+ auto out() { return _M_sink.out(); }
+ };
+#endif
+} // namespace __format
+
inline void
vprint_nonunicode(FILE* __stream, string_view __fmt, format_args __args)
{
+ std::vformat_to(__format::_File_sink(__stream, false).out(), __fmt, __args);
+ }
+
+ inline void
+ vprint_nonunicode_buffered(FILE* __stream, string_view __fmt,
+ format_args __args)
+ {
__format::_Str_sink<char> __buf;
std::vformat_to(__buf.out(), __fmt, __args);
auto __out = __buf.view();
@@ -73,14 +278,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#else
__format::_Str_sink<char> __buf;
std::vformat_to(__buf.out(), __fmt, __args);
- auto __out = __buf.view();
+ auto __out = __buf._M_span();
void* __open_terminal(FILE*);
error_code __write_to_terminal(void*, span<char>);
// If stream refers to a terminal, write a native Unicode string to it.
if (auto __term = __open_terminal(__stream))
{
- string __out = std::vformat(__fmt, __args);
error_code __e;
if (!std::fflush(__stream))
{
@@ -95,21 +299,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_THROW_OR_ABORT(system_error(__e, "std::vprint_unicode"));
}
- // Otherwise just write the string to the file as vprint_nonunicode does.
+ // Otherwise just write the string to the file.
if (std::fwrite(__out.data(), 1, __out.size(), __stream) != __out.size())
__throw_system_error(EIO);
#endif
}
+ inline void
+ vprint_unicode_buffered(FILE* __stream, string_view __fmt, format_args __args)
+ {
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // For most targets we don't need to do anything special to write
+ // Unicode to a terminal. Just use the nonunicode function.
+ std::vprint_nonunicode_buffered(__stream, __fmt, __args);
+#else
+ // For Windows the locking function formats everything first anyway,
+ // so no formatting happens while a lock is taken. Just use that.
+ std::vprint_unicode(__stream, __fmt, __args);
+#endif
+ }
+
template<typename... _Args>
inline void
print(FILE* __stream, format_string<_Args...> __fmt, _Args&&... __args)
{
+ constexpr bool __locksafe =
+ (enable_nonlocking_formatter_optimization<remove_cvref_t<_Args>> && ...);
+
auto __fmtargs = std::make_format_args(__args...);
+#if defined(_WIN32) && !defined(__CYGWIN__)
if constexpr (__unicode::__literal_encoding_is_utf8())
- std::vprint_unicode(__stream, __fmt.get(), __fmtargs);
+ std::vprint_unicode_buffered(__stream, __fmt.get(), __fmtargs);
else
+#endif
+
+ if constexpr (__locksafe)
std::vprint_nonunicode(__stream, __fmt.get(), __fmtargs);
+ else
+ std::vprint_nonunicode_buffered(__stream, __fmt.get(), __fmtargs);
}
template<typename... _Args>
@@ -121,8 +348,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline void
println(FILE* __stream, format_string<_Args...> __fmt, _Args&&... __args)
{
- std::print(__stream, "{}\n",
- std::format(__fmt, std::forward<_Args>(__args)...));
+ constexpr bool __locksafe =
+ (enable_nonlocking_formatter_optimization<remove_cvref_t<_Args>> && ...);
+
+ // The standard wants us to call
+ // print(stream, runtime_format(string(fmt.get()) + '\n'), args...)
+ // here, but we can avoid that string concatenation in most cases,
+ // and we know what that would call, so we can call that directly.
+
+ auto __fmtargs = std::make_format_args(__args...);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if constexpr (__unicode::__literal_encoding_is_utf8())
+ {
+ // We can't avoid the string concatenation here, but we can call
+ // vprint_unicode_buffered directly, since that's what print would do.
+ string __fmtn;
+ __fmtn.reserve(__fmt.get().size() + 1);
+ __fmtn = __fmt.get();
+ __fmtn += '\n';
+ std::vprint_unicode_buffered(__stream, __fmtn, __fmtargs);
+ }
+ else
+#endif
+
+ // For non-Windows and for non-Unicode on Windows, we know that print
+ // would call vprint_nonunicode or vprint_nonunicode_buffered with a
+ // newline appended to the format-string. Use a _File_sink that adds
+ // the newline automatically and write to it directly.
+ if constexpr (__locksafe)
+ std::vformat_to(__format::_File_sink(__stream, true).out(),
+ __fmt.get(), __fmtargs);
+ else
+ {
+ // Format to a string buffer first, then write the result to a
+ // _File_sink that adds a newline.
+ __format::_Str_sink<char> __buf;
+ std::vformat_to(__buf.out(), __fmt.get(), __fmtargs);
+ string_view __s(__buf.view());
+ __format::_File_sink(__stream, true).out() = __s;
+ }
}
template<typename... _Args>
@@ -131,19 +395,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ std::println(stdout, __fmt, std::forward<_Args>(__args)...); }
inline void
- vprint_unicode(string_view __fmt, format_args __args)
- { std::vprint_unicode(stdout, __fmt, __args); }
+ vprint_unicode_buffered(string_view __fmt, format_args __args)
+ { std::vprint_unicode_buffered(stdout, __fmt, __args); }
inline void
- vprint_nonunicode(string_view __fmt, format_args __args)
- { std::vprint_nonunicode(stdout, __fmt, __args); }
+ vprint_nonunicode_buffered(string_view __fmt, format_args __args)
+ { std::vprint_nonunicode_buffered(stdout, __fmt, __args); }
// Defined for C++26, supported as an extension to C++23.
inline void println(FILE* __stream)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
if constexpr (__unicode::__literal_encoding_is_utf8())
- std::vprint_unicode(__stream, "\n", std::make_format_args());
+ std::vprint_unicode_buffered(__stream, "\n", std::make_format_args());
else
#endif
if (std::putc('\n', __stream) == EOF)
diff --git a/libstdc++-v3/include/std/queue b/libstdc++-v3/include/std/queue
index 74b6c07..bf2b344 100644
--- a/libstdc++-v3/include/std/queue
+++ b/libstdc++-v3/include/std/queue
@@ -61,14 +61,111 @@
#include <bits/requires_hosted.h> // containers
+#define __glibcxx_want_adaptor_iterator_pair_constructor
+#define __glibcxx_want_containers_ranges
+#include <bits/version.h>
+
#include <deque>
#include <vector>
#include <bits/stl_heap.h>
#include <bits/stl_function.h>
#include <bits/stl_queue.h>
-#define __glibcxx_want_adaptor_iterator_pair_constructor
-#define __glibcxx_want_containers_ranges
-#include <bits/version.h>
+#ifdef __glibcxx_format_ranges // C++ >= 23 && HOSTED
+#include <bits/formatfwd.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ // Standard does not constrain accepted _CharT, we do so we can
+ // befriend specializations.
+ template<__format::__char _CharT, typename _Tp,
+ formattable<_CharT> _Container>
+ struct formatter<queue<_Tp, _Container>, _CharT>
+ {
+ private:
+ using __maybe_const_adaptor
+ = __conditional_t<
+ __format::__const_formattable_range<_Container, _CharT>,
+ const queue<_Tp, _Container>, queue<_Tp, _Container>>;
+
+ public:
+ // Standard declares this as template accepting unconstrained
+ // ParseContext type.
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ { return _M_f.parse(__pc); }
+
+ // Standard declares this as template accepting unconstrained
+ // FormatContext type.
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__maybe_const_adaptor& __a,
+ basic_format_context<_Out, _CharT>& __fc) const
+ { return _M_f.format(__a.c, __fc); }
+
+ private:
+ // Standard uses formatter<ref_view<_Container>, _CharT>, but range_formatter
+ // provides same behavior.
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3881. Incorrect formatting of container adapters backed by std::string
+ range_formatter<_Tp, _CharT> _M_f;
+ };
+
+#if __glibcxx_print >= 202406L
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4398. enable_nonlocking_formatter_optimization should be disabled for container adaptors
+ template<typename _Tp, typename _Container>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<queue<_Tp, _Container>> = false;
+#endif
+
+ template<__format::__char _CharT, typename _Tp,
+ formattable<_CharT> _Container, typename _Compare>
+ struct formatter<priority_queue<_Tp, _Container, _Compare>, _CharT>
+ {
+ private:
+ using __maybe_const_adaptor
+ = __conditional_t<
+ __format::__const_formattable_range<_Container, _CharT>,
+ const priority_queue<_Tp, _Container, _Compare>,
+ priority_queue<_Tp, _Container, _Compare>>;
+
+ public:
+ // Standard declares this as template accepting unconstrained
+ // ParseContext type.
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ { return _M_f.parse(__pc); }
+
+ // Standard declares this as template accepting unconstrained
+ // FormatContext type.
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__maybe_const_adaptor& __a,
+ basic_format_context<_Out, _CharT>& __fc) const
+ { return _M_f.format(__a.c, __fc); }
+
+ private:
+ // Standard uses formatter<ref_view<_Container>, _CharT>, but range_formatter
+ // provides same behavior.
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3881. Incorrect formatting of container adapters backed by std::string
+ range_formatter<_Tp, _CharT> _M_f;
+ };
+
+#if __glibcxx_print >= 202406L
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4398. enable_nonlocking_formatter_optimization should be disabled for container adaptors
+ template<typename _Tp, typename _Container, typename _Comparator>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<
+ priority_queue<_Tp, _Container, _Comparator>> = false;
+#endif
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // __glibcxx_format_ranges
+
#endif /* _GLIBCXX_QUEUE */
diff --git a/libstdc++-v3/include/std/random b/libstdc++-v3/include/std/random
index 0e058a0..8a02ade 100644
--- a/libstdc++-v3/include/std/random
+++ b/libstdc++-v3/include/std/random
@@ -39,6 +39,9 @@
# include <bits/c++0x_warning.h>
#else
+#define __glibcxx_want_philox_engine
+#include <bits/version.h>
+
#include <cmath>
#include <cstdint> // For uint_fast32_t, uint_fast64_t, uint_least32_t
#include <cstdlib>
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 9300c36..b81ee78 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -51,6 +51,7 @@
#include <utility>
#include <variant>
#endif
+#include <bits/binders.h>
#include <bits/ranges_util.h>
#include <bits/refwrap.h>
@@ -64,6 +65,7 @@
#define __glibcxx_want_ranges_chunk
#define __glibcxx_want_ranges_chunk_by
#define __glibcxx_want_ranges_enumerate
+#define __glibcxx_want_ranges_indices
#define __glibcxx_want_ranges_join_with
#define __glibcxx_want_ranges_repeat
#define __glibcxx_want_ranges_slide
@@ -284,6 +286,190 @@ namespace ranges
operator->() const noexcept
{ return std::__addressof(_M_value); }
};
+
+ template<template<typename> class>
+ constexpr bool __is_std_op_template = false;
+
+ template<>
+ inline constexpr bool __is_std_op_template<std::equal_to> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::not_equal_to> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::greater> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::less> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::greater_equal> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::less_equal> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::plus> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::minus> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::multiplies> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::divides> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::modulus> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::negate> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::logical_and> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::logical_or> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::logical_not> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::bit_and> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::bit_or> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::bit_xor> = true;
+ template<>
+ inline constexpr bool __is_std_op_template<std::bit_not> = true;
+
+
+ template<typename _Fn>
+ constexpr bool __is_std_op_wrapper = false;
+
+ template<template<typename> class _Ft, typename _Tp>
+ constexpr bool __is_std_op_wrapper<_Ft<_Tp>>
+ = __is_std_op_template<_Ft>;
+
+ namespace __func_handle
+ {
+ template<typename _Fn>
+ struct _Inplace
+ {
+ _Inplace() = default;
+
+ constexpr explicit
+ _Inplace(_Fn __func) noexcept
+ : _M_fn(__func)
+ { }
+
+ template<typename... _Iters>
+ constexpr decltype(auto)
+ _M_call_deref(const _Iters&... __iters) const
+ noexcept(noexcept(_M_fn(*__iters...)))
+ { return _M_fn(*__iters...); }
+
+ template<typename _DistType, typename... _Iters>
+ constexpr decltype(auto)
+ _M_call_subscript(const _DistType __n, const _Iters&... __iters) const
+ noexcept(noexcept(_M_fn(__iters[iter_difference_t<_Iters>(__n)]...)))
+ { return _M_fn(__iters[iter_difference_t<_Iters>(__n)]...); }
+
+ private:
+ [[no_unique_address]] _Fn _M_fn = _Fn();
+ };
+
+ template<typename _Fn>
+ struct _InplaceMemPtr
+ {
+ _InplaceMemPtr() = default;
+
+ constexpr explicit
+ _InplaceMemPtr(_Fn __func) noexcept
+ : _M_ptr(__func)
+ {}
+
+ template<typename... _Iters>
+ constexpr decltype(auto)
+ _M_call_deref(const _Iters&... __iters) const
+ noexcept(noexcept(std::__invoke(_M_ptr, *__iters...)))
+ { return std::__invoke(_M_ptr, *__iters...); }
+
+ template<typename _DistType, typename... _Iters>
+ constexpr decltype(auto)
+ _M_call_subscript(const _DistType __n, const _Iters&... __iters) const
+ noexcept(noexcept(std::__invoke(_M_ptr, __iters[iter_difference_t<_Iters>(__n)]...)))
+ { return std::__invoke(_M_ptr, __iters[iter_difference_t<_Iters>(__n)]...); }
+
+ private:
+ _Fn _M_ptr = nullptr;
+ };
+
+ template<typename _Fn>
+ struct _ViaPointer
+ {
+ _ViaPointer() = default;
+
+ constexpr explicit
+ _ViaPointer(_Fn& __func) noexcept
+ : _M_ptr(std::addressof(__func))
+ { }
+
+ template<typename _Un>
+ requires (!is_const_v<_Un>) && is_same_v<const _Un, _Fn>
+ constexpr
+ _ViaPointer(_ViaPointer<_Un> __other) noexcept
+ : _M_ptr(__other._M_ptr)
+ { }
+
+ template<typename... _Iters>
+ constexpr decltype(auto)
+ _M_call_deref(const _Iters&... __iters) const
+ noexcept(noexcept((*_M_ptr)(*__iters...)))
+ { return (*_M_ptr)(*__iters...); }
+
+ template<typename _DistType, typename... _Iters>
+ constexpr decltype(auto)
+ _M_call_subscript(const _DistType __n, const _Iters&... __iters) const
+ noexcept(noexcept((*_M_ptr)(__iters[iter_difference_t<_Iters>(__n)]...)))
+ { return (*_M_ptr)(__iters[iter_difference_t<_Iters>(__n)]...); }
+
+ private:
+ _Fn* _M_ptr = nullptr;
+
+ template<typename>
+ friend struct _ViaPointer;
+ };
+
+ template<typename _Fn>
+ struct _StaticCall
+ {
+ _StaticCall() = default;
+
+ constexpr explicit
+ _StaticCall(const _Fn&) noexcept
+ {}
+
+ template<typename... _Iters>
+ static constexpr decltype(auto)
+ _M_call_deref(const _Iters&... __iters)
+ noexcept(noexcept(_Fn::operator()(*__iters...)))
+ { return _Fn::operator()(*__iters...); }
+
+ template<typename _DistType, typename... _Iters>
+ static constexpr decltype(auto)
+ _M_call_subscript(_DistType __n, const _Iters&... __iters)
+ noexcept(noexcept(_Fn::operator()(__iters[iter_difference_t<_Iters>(__n)]...)))
+ { return _Fn::operator()(__iters[iter_difference_t<_Iters>(__n)]...); }
+ };
+
+ template<typename _Fn, typename... _Iters>
+ consteval auto
+ __select()
+ {
+ using _Fd = remove_cv_t<_Fn>;
+ if constexpr (is_member_pointer_v<_Fd>)
+ return __func_handle::_InplaceMemPtr<_Fd>();
+ else if constexpr (is_function_v<remove_pointer_t<_Fd>>)
+ return __func_handle::_Inplace<_Fd>();
+ else if constexpr (__is_std_op_wrapper<_Fd>)
+ return __func_handle::_Inplace<_Fd>();
+ else if constexpr (requires (const _Iters&... __iters)
+ { _Fd::operator()(*__iters...); })
+ return __func_handle::_StaticCall<_Fd>();
+ else
+ return __func_handle::_ViaPointer<_Fn>();
+ };
+ } // __func_handle
+
+ template<typename _Fn, typename... _Iters>
+ using __func_handle_t = decltype(__func_handle::__select<_Fn, _Iters...>());
} // namespace __detail
/// A view that contains exactly one element.
@@ -660,7 +846,7 @@ namespace ranges
: _M_value(__value)
{ }
- constexpr
+ constexpr explicit
iota_view(type_identity_t<_Winc> __value,
type_identity_t<_Bound> __bound)
: _M_value(__value), _M_bound(__bound)
@@ -669,19 +855,19 @@ namespace ranges
__glibcxx_assert( bool(__value <= __bound) );
}
- constexpr
+ constexpr explicit
iota_view(_Iterator __first, _Iterator __last)
requires same_as<_Winc, _Bound>
: iota_view(__first._M_value, __last._M_value)
{ }
- constexpr
+ constexpr explicit
iota_view(_Iterator __first, unreachable_sentinel_t __last)
requires same_as<_Bound, unreachable_sentinel_t>
: iota_view(__first._M_value, __last)
{ }
- constexpr
+ constexpr explicit
iota_view(_Iterator __first, _Sentinel __last)
requires (!same_as<_Winc, _Bound>) && (!same_as<_Bound, unreachable_sentinel_t>)
: iota_view(__first._M_value, __last._M_bound)
@@ -784,6 +970,19 @@ namespace views
};
inline constexpr _Iota iota{};
+
+#ifdef __cpp_lib_ranges_indices // C++ >= 26
+ struct _Indices
+ {
+ template<ranges::__detail::__is_integer_like _Tp>
+ requires __detail::__can_iota_view<_Tp>
+ [[nodiscard]] constexpr auto
+ operator() (_Tp __e) const noexcept
+ { return iota(_Tp{}, __e); }
+ };
+
+ inline constexpr _Indices indices{};
+#endif // __cpp_lib_ranges_indices
} // namespace views
#if _GLIBCXX_HOSTED
@@ -1047,93 +1246,43 @@ namespace views::__adaptor
template<typename _Adaptor, typename... _Args>
struct _Partial : _RangeAdaptorClosure<_Partial<_Adaptor, _Args...>>
{
- tuple<_Args...> _M_args;
+ using _Binder = _Bind_back_t<_Adaptor, _Args...>;
+ [[no_unique_address]] _Binder _M_binder;
// First parameter is to ensure this constructor is never used
// instead of the copy/move constructor.
template<typename... _Ts>
constexpr
_Partial(int, _Ts&&... __args)
- : _M_args(std::forward<_Ts>(__args)...)
+ : _M_binder(0, _Adaptor(), std::forward<_Ts>(__args)...)
{ }
// Invoke _Adaptor with arguments __r, _M_args... according to the
// value category of this _Partial object.
-#if __cpp_explicit_this_parameter
+#if _GLIBCXX_EXPLICIT_THIS_PARAMETER
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this
template<typename _Self, typename _Range>
requires __adaptor_invocable<_Adaptor, _Range, __like_t<_Self, _Args>...>
constexpr auto
operator()(this _Self&& __self, _Range&& __r)
{
- auto __forwarder = [&__r] (auto&&... __args) {
- return _Adaptor{}(std::forward<_Range>(__r),
- std::forward<decltype(__args)>(__args)...);
- };
- return std::apply(__forwarder, __like_t<_Self, _Partial>(__self)._M_args);
+ return _Binder::_S_call(__like_t<_Self, _Partial>(__self)._M_binder,
+ std::forward<_Range>(__r));
}
+# pragma GCC diagnostic pop
#else
template<typename _Range>
requires __adaptor_invocable<_Adaptor, _Range, const _Args&...>
constexpr auto
operator()(_Range&& __r) const &
- {
- auto __forwarder = [&__r] (const auto&... __args) {
- return _Adaptor{}(std::forward<_Range>(__r), __args...);
- };
- return std::apply(__forwarder, _M_args);
- }
+ { return _Binder::_S_call(_M_binder, std::forward<_Range>(__r)); }
template<typename _Range>
requires __adaptor_invocable<_Adaptor, _Range, _Args...>
constexpr auto
operator()(_Range&& __r) &&
- {
- auto __forwarder = [&__r] (auto&... __args) {
- return _Adaptor{}(std::forward<_Range>(__r), std::move(__args)...);
- };
- return std::apply(__forwarder, _M_args);
- }
-
- template<typename _Range>
- constexpr auto
- operator()(_Range&& __r) const && = delete;
-#endif
- };
-
- // A lightweight specialization of the above primary template for
- // the common case where _Adaptor accepts a single extra argument.
- template<typename _Adaptor, typename _Arg>
- struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure<_Partial<_Adaptor, _Arg>>
- {
- _Arg _M_arg;
-
- template<typename _Tp>
- constexpr
- _Partial(int, _Tp&& __arg)
- : _M_arg(std::forward<_Tp>(__arg))
- { }
-
-#if __cpp_explicit_this_parameter
- template<typename _Self, typename _Range>
- requires __adaptor_invocable<_Adaptor, _Range, __like_t<_Self, _Arg>>
- constexpr auto
- operator()(this _Self&& __self, _Range&& __r)
- {
- return _Adaptor{}(std::forward<_Range>(__r),
- __like_t<_Self, _Partial>(__self)._M_arg);
- }
-#else
- template<typename _Range>
- requires __adaptor_invocable<_Adaptor, _Range, const _Arg&>
- constexpr auto
- operator()(_Range&& __r) const &
- { return _Adaptor{}(std::forward<_Range>(__r), _M_arg); }
-
- template<typename _Range>
- requires __adaptor_invocable<_Adaptor, _Range, _Arg>
- constexpr auto
- operator()(_Range&& __r) &&
- { return _Adaptor{}(std::forward<_Range>(__r), std::move(_M_arg)); }
+ { return _Binder::_S_call(std::move(_M_binder), std::forward<_Range>(__r)); }
template<typename _Range>
constexpr auto
@@ -1150,12 +1299,13 @@ namespace views::__adaptor
&& (is_trivially_copy_constructible_v<_Args> && ...)
struct _Partial<_Adaptor, _Args...> : _RangeAdaptorClosure<_Partial<_Adaptor, _Args...>>
{
- tuple<_Args...> _M_args;
+ using _Binder = _Bind_back_t<_Adaptor, _Args...>;
+ [[no_unique_address]] _Binder _M_binder;
template<typename... _Ts>
constexpr
_Partial(int, _Ts&&... __args)
- : _M_args(std::forward<_Ts>(__args)...)
+ : _M_binder(0, _Adaptor(), std::forward<_Ts>(__args)...)
{ }
// Invoke _Adaptor with arguments __r, const _M_args&... regardless
@@ -1164,36 +1314,7 @@ namespace views::__adaptor
requires __adaptor_invocable<_Adaptor, _Range, const _Args&...>
constexpr auto
operator()(_Range&& __r) const
- {
- auto __forwarder = [&__r] (const auto&... __args) {
- return _Adaptor{}(std::forward<_Range>(__r), __args...);
- };
- return std::apply(__forwarder, _M_args);
- }
-
- static constexpr bool _S_has_simple_call_op = true;
- };
-
- // A lightweight specialization of the above template for the common case
- // where _Adaptor accepts a single extra argument.
- template<typename _Adaptor, typename _Arg>
- requires __adaptor_has_simple_extra_args<_Adaptor, _Arg>
- && is_trivially_copy_constructible_v<_Arg>
- struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure<_Partial<_Adaptor, _Arg>>
- {
- _Arg _M_arg;
-
- template<typename _Tp>
- constexpr
- _Partial(int, _Tp&& __arg)
- : _M_arg(std::forward<_Tp>(__arg))
- { }
-
- template<typename _Range>
- requires __adaptor_invocable<_Adaptor, _Range, const _Arg&>
- constexpr auto
- operator()(_Range&& __r) const
- { return _Adaptor{}(std::forward<_Range>(__r), _M_arg); }
+ { return _Binder::_S_call(_M_binder, std::forward<_Range>(__r)); }
static constexpr bool _S_has_simple_call_op = true;
};
@@ -1218,7 +1339,9 @@ namespace views::__adaptor
// Invoke _M_rhs(_M_lhs(__r)) according to the value category of this
// range adaptor closure object.
-#if __cpp_explicit_this_parameter
+#if _GLIBCXX_EXPLICIT_THIS_PARAMETER
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this
template<typename _Self, typename _Range>
requires __pipe_invocable<__like_t<_Self, _Lhs>, __like_t<_Self, _Rhs>, _Range>
constexpr auto
@@ -1228,6 +1351,7 @@ namespace views::__adaptor
(__like_t<_Self, _Pipe>(__self)._M_lhs
(std::forward<_Range>(__r))));
}
+# pragma GCC diagnostic pop
#else
template<typename _Range>
requires __pipe_invocable<const _Lhs&, const _Rhs&, _Range>
@@ -1585,8 +1709,6 @@ namespace views::__adaptor
};
template<random_access_range _Range>
- requires (sizeof(range_difference_t<_Range>)
- <= sizeof(iterator_t<_Range>))
struct _CachedPosition<_Range>
{
private:
@@ -1811,7 +1933,7 @@ namespace views::__adaptor
&& default_initializable<_Pred>)
= default;
- constexpr
+ constexpr explicit
filter_view(_Vp __base, _Pred __pred)
: _M_base(std::move(__base)), _M_pred(std::move(__pred))
{ }
@@ -1942,6 +2064,10 @@ namespace views::__adaptor
private:
using _Parent = __detail::__maybe_const_t<_Const, transform_view>;
using _Base = transform_view::_Base<_Const>;
+ using _Base_iter = iterator_t<_Base>;
+ using _Func_handle = __detail::__func_handle_t<
+ __detail::__maybe_const_t<_Const, _Fp>,
+ _Base_iter>;
static auto
_S_iter_concept()
@@ -1956,10 +2082,8 @@ namespace views::__adaptor
return input_iterator_tag{};
}
- using _Base_iter = iterator_t<_Base>;
-
_Base_iter _M_current = _Base_iter();
- _Parent* _M_parent = nullptr;
+ [[no_unique_address]] _Func_handle _M_fun;
public:
using iterator_concept = decltype(_S_iter_concept());
@@ -1972,16 +2096,20 @@ namespace views::__adaptor
_Iterator() requires default_initializable<_Base_iter> = default;
constexpr
- _Iterator(_Parent* __parent, _Base_iter __current)
- : _M_current(std::move(__current)),
- _M_parent(__parent)
+ _Iterator(_Func_handle __fun, _Base_iter __current)
+ : _M_current(std::move(__current)), _M_fun(__fun)
{ }
constexpr
+ _Iterator(_Parent* __parent, _Base_iter __current)
+ : _M_current(std::move(__current)), _M_fun(*__parent->_M_fun)
+ {}
+
+ constexpr
_Iterator(_Iterator<!_Const> __i)
requires _Const
&& convertible_to<iterator_t<_Vp>, _Base_iter>
- : _M_current(std::move(__i._M_current)), _M_parent(__i._M_parent)
+ : _M_current(std::move(__i._M_current)), _M_fun(__i._M_fun)
{ }
constexpr const _Base_iter&
@@ -1994,8 +2122,8 @@ namespace views::__adaptor
constexpr decltype(auto)
operator*() const
- noexcept(noexcept(std::__invoke(*_M_parent->_M_fun, *_M_current)))
- { return std::__invoke(*_M_parent->_M_fun, *_M_current); }
+ noexcept(noexcept(_M_fun._M_call_deref(_M_current)))
+ { return _M_fun._M_call_deref(_M_current); }
constexpr _Iterator&
operator++()
@@ -2048,7 +2176,7 @@ namespace views::__adaptor
constexpr decltype(auto)
operator[](difference_type __n) const
requires random_access_range<_Base>
- { return std::__invoke(*_M_parent->_M_fun, _M_current[__n]); }
+ { return _M_fun._M_call_subscript(__n, _M_current); }
friend constexpr bool
operator==(const _Iterator& __x, const _Iterator& __y)
@@ -2086,17 +2214,17 @@ namespace views::__adaptor
friend constexpr _Iterator
operator+(_Iterator __i, difference_type __n)
requires random_access_range<_Base>
- { return {__i._M_parent, __i._M_current + __n}; }
+ { return {__i._M_fun, __i._M_current + __n}; }
friend constexpr _Iterator
operator+(difference_type __n, _Iterator __i)
requires random_access_range<_Base>
- { return {__i._M_parent, __i._M_current + __n}; }
+ { return {__i._M_fun, __i._M_current + __n}; }
friend constexpr _Iterator
operator-(_Iterator __i, difference_type __n)
requires random_access_range<_Base>
- { return {__i._M_parent, __i._M_current - __n}; }
+ { return {__i._M_fun, __i._M_current - __n}; }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3483. transform_view::iterator's difference is overconstrained
@@ -2188,7 +2316,7 @@ namespace views::__adaptor
&& default_initializable<_Fp>)
= default;
- constexpr
+ constexpr explicit
transform_view(_Vp __base, _Fp __fun)
: _M_base(std::move(__base)), _M_fun(std::move(__fun))
{ }
@@ -2323,7 +2451,7 @@ namespace views::__adaptor
public:
take_view() requires default_initializable<_Vp> = default;
- constexpr
+ constexpr explicit
take_view(_Vp __base, range_difference_t<_Vp> __count)
: _M_base(std::move(__base)), _M_count(std::move(__count))
{ }
@@ -2471,6 +2599,10 @@ namespace views::__adaptor
using _Tp = remove_cvref_t<_Range>;
if constexpr (__detail::__is_empty_view<_Tp>)
return _Tp();
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ else if constexpr (__is_optional_v<_Tp> && view<_Tp>)
+ return __n ? std::forward<_Range>(__r) : _Tp();
+#endif
else if constexpr (random_access_range<_Tp>
&& sized_range<_Tp>
&& (std::__detail::__is_span<_Tp>
@@ -2562,7 +2694,7 @@ namespace views::__adaptor
&& default_initializable<_Pred>)
= default;
- constexpr
+ constexpr explicit
take_while_view(_Vp __base, _Pred __pred)
: _M_base(std::move(__base)), _M_pred(std::move(__pred))
{ }
@@ -2650,7 +2782,7 @@ namespace views::__adaptor
public:
drop_view() requires default_initializable<_Vp> = default;
- constexpr
+ constexpr explicit
drop_view(_Vp __base, range_difference_t<_Vp> __count)
: _M_base(std::move(__base)), _M_count(__count)
{ __glibcxx_assert(__count >= 0); }
@@ -2747,6 +2879,10 @@ namespace views::__adaptor
using _Tp = remove_cvref_t<_Range>;
if constexpr (__detail::__is_empty_view<_Tp>)
return _Tp();
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ else if constexpr (__is_optional_v<_Tp> && view<_Tp>)
+ return __n ? _Tp() : std::forward<_Range>(__r);
+#endif
else if constexpr (random_access_range<_Tp>
&& sized_range<_Tp>
&& (std::__detail::__is_span<_Tp>
@@ -2804,7 +2940,7 @@ namespace views::__adaptor
&& default_initializable<_Pred>)
= default;
- constexpr
+ constexpr explicit
drop_while_view(_Vp __base, _Pred __pred)
: _M_base(std::move(__base)), _M_pred(std::move(__pred))
{ }
@@ -2971,7 +3107,12 @@ namespace views::__adaptor
}
if constexpr (_S_ref_is_glvalue)
- _M_inner.reset();
+ {
+ if constexpr (forward_iterator<_Inner_iter>)
+ _M_inner = _Inner_iter();
+ else
+ _M_inner.reset();
+ }
}
static constexpr auto
@@ -3011,6 +3152,24 @@ namespace views::__adaptor
return *_M_parent->_M_outer;
}
+ constexpr _Inner_iter&
+ _M_get_inner() noexcept
+ {
+ if constexpr (forward_iterator<_Inner_iter>)
+ return _M_inner;
+ else
+ return *_M_inner;
+ }
+
+ constexpr const _Inner_iter&
+ _M_get_inner() const noexcept
+ {
+ if constexpr (forward_iterator<_Inner_iter>)
+ return _M_inner;
+ else
+ return *_M_inner;
+ }
+
constexpr
_Iterator(_Parent* __parent, _Outer_iter __outer) requires forward_range<_Base>
: _M_outer(std::move(__outer)), _M_parent(__parent)
@@ -3022,8 +3181,11 @@ namespace views::__adaptor
{ _M_satisfy(); }
[[no_unique_address]]
- __detail::__maybe_present_t<forward_range<_Base>, _Outer_iter> _M_outer;
- optional<_Inner_iter> _M_inner;
+ __detail::__maybe_present_t<forward_range<_Base>, _Outer_iter> _M_outer
+ = decltype(_M_outer)();
+ __conditional_t<forward_iterator<_Inner_iter>,
+ _Inner_iter, optional<_Inner_iter>> _M_inner
+ = decltype(_M_inner)();
_Parent* _M_parent = nullptr;
public:
@@ -3047,7 +3209,7 @@ namespace views::__adaptor
constexpr decltype(auto)
operator*() const
- { return **_M_inner; }
+ { return *_M_get_inner(); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3500. join_view::iterator::operator->() is bogus
@@ -3055,7 +3217,7 @@ namespace views::__adaptor
operator->() const
requires __detail::__has_arrow<_Inner_iter>
&& copyable<_Inner_iter>
- { return *_M_inner; }
+ { return _M_get_inner(); }
constexpr _Iterator&
operator++()
@@ -3066,7 +3228,7 @@ namespace views::__adaptor
else
return *_M_parent->_M_inner;
}();
- if (++*_M_inner == ranges::end(__inner_range))
+ if (++_M_get_inner() == ranges::end(__inner_range))
{
++_M_get_outer();
_M_satisfy();
@@ -3096,9 +3258,9 @@ namespace views::__adaptor
{
if (_M_outer == ranges::end(_M_parent->_M_base))
_M_inner = ranges::end(__detail::__as_lvalue(*--_M_outer));
- while (*_M_inner == ranges::begin(__detail::__as_lvalue(*_M_outer)))
- *_M_inner = ranges::end(__detail::__as_lvalue(*--_M_outer));
- --*_M_inner;
+ while (_M_get_inner() == ranges::begin(__detail::__as_lvalue(*_M_outer)))
+ _M_get_inner() = ranges::end(__detail::__as_lvalue(*--_M_outer));
+ --_M_get_inner();
return *this;
}
@@ -3125,14 +3287,14 @@ namespace views::__adaptor
friend constexpr decltype(auto)
iter_move(const _Iterator& __i)
- noexcept(noexcept(ranges::iter_move(*__i._M_inner)))
- { return ranges::iter_move(*__i._M_inner); }
+ noexcept(noexcept(ranges::iter_move(__i._M_get_inner())))
+ { return ranges::iter_move(__i._M_get_inner()); }
friend constexpr void
iter_swap(const _Iterator& __x, const _Iterator& __y)
- noexcept(noexcept(ranges::iter_swap(*__x._M_inner, *__y._M_inner)))
+ noexcept(noexcept(ranges::iter_swap(__x._M_get_inner(), __y._M_get_inner())))
requires indirectly_swappable<_Inner_iter>
- { return ranges::iter_swap(*__x._M_inner, *__y._M_inner); }
+ { return ranges::iter_swap(__x._M_get_inner(), __y._M_get_inner()); }
friend _Iterator<!_Const>;
template<bool> friend struct _Sentinel;
@@ -3376,7 +3538,8 @@ namespace views::__adaptor
[[no_unique_address]]
__detail::__maybe_present_t<forward_range<_Vp>,
- iterator_t<_Base>> _M_current;
+ iterator_t<_Base>> _M_current
+ = decltype(_M_current)();
bool _M_trailing_empty = false;
public:
@@ -3641,7 +3804,7 @@ namespace views::__adaptor
&& default_initializable<_Pattern>)
= default;
- constexpr
+ constexpr explicit
lazy_split_view(_Vp __base, _Pattern __pattern)
: _M_base(std::move(__base)), _M_pattern(std::move(__pattern))
{ }
@@ -3649,7 +3812,7 @@ namespace views::__adaptor
template<input_range _Range>
requires constructible_from<_Vp, views::all_t<_Range>>
&& constructible_from<_Pattern, single_view<range_value_t<_Range>>>
- constexpr
+ constexpr explicit
lazy_split_view(_Range&& __r, range_value_t<_Range> __e)
: _M_base(views::all(std::forward<_Range>(__r))),
_M_pattern(views::single(std::move(__e)))
@@ -3766,7 +3929,7 @@ namespace views::__adaptor
&& default_initializable<_Pattern>)
= default;
- constexpr
+ constexpr explicit
split_view(_Vp __base, _Pattern __pattern)
: _M_base(std::move(__base)), _M_pattern(std::move(__pattern))
{ }
@@ -3774,7 +3937,7 @@ namespace views::__adaptor
template<forward_range _Range>
requires constructible_from<_Vp, views::all_t<_Range>>
&& constructible_from<_Pattern, single_view<range_value_t<_Range>>>
- constexpr
+ constexpr explicit
split_view(_Range&& __r, range_value_t<_Range> __e)
: _M_base(views::all(std::forward<_Range>(__r))),
_M_pattern(views::single(std::move(__e)))
@@ -4197,6 +4360,10 @@ namespace views::__adaptor
using _Tp = remove_cvref_t<_Range>;
if constexpr (__detail::__is_reverse_view<_Tp>)
return std::forward<_Range>(__r).base();
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ else if constexpr (__is_optional_v<_Tp> && view<_Tp>)
+ return std::forward<_Range>(__r);
+#endif
else if constexpr (__detail::__is_reversible_subrange<_Tp>)
{
using _Iter = decltype(ranges::begin(__r).base());
@@ -5155,13 +5322,21 @@ namespace views::__adaptor
class zip_transform_view<_Fp, _Vs...>::_Iterator : public __iter_cat<_Const>
{
using _Parent = __detail::__maybe_const_t<_Const, zip_transform_view>;
+ using _Fun_handle = __detail::__func_handle_t<
+ __detail::__maybe_const_t<_Const, _Fp>,
+ iterator_t<__detail::__maybe_const_t<_Const, _Vs>>...>;
- _Parent* _M_parent = nullptr;
+ [[no_unique_address]] _Fun_handle _M_fun;
__ziperator<_Const> _M_inner;
constexpr
+ _Iterator(_Fun_handle __fun, __ziperator<_Const> __inner)
+ : _M_fun(__fun), _M_inner(std::move(__inner))
+ { }
+
+ constexpr
_Iterator(_Parent& __parent, __ziperator<_Const> __inner)
- : _M_parent(std::__addressof(__parent)), _M_inner(std::move(__inner))
+ : _M_fun(*__parent._M_fun), _M_inner(std::move(__inner))
{ }
friend class zip_transform_view;
@@ -5179,14 +5354,14 @@ namespace views::__adaptor
constexpr
_Iterator(_Iterator<!_Const> __i)
requires _Const && convertible_to<__ziperator<false>, __ziperator<_Const>>
- : _M_parent(__i._M_parent), _M_inner(std::move(__i._M_inner))
+ : _M_fun(__i._M_fun), _M_inner(std::move(__i._M_inner))
{ }
constexpr decltype(auto)
operator*() const
{
return std::apply([&](const auto&... __iters) -> decltype(auto) {
- return std::__invoke(*_M_parent->_M_fun, *__iters...);
+ return _M_fun._M_call_deref(__iters...);
}, _M_inner._M_current);
}
@@ -5242,7 +5417,7 @@ namespace views::__adaptor
operator[](difference_type __n) const requires random_access_range<_Base<_Const>>
{
return std::apply([&]<typename... _Is>(const _Is&... __iters) -> decltype(auto) {
- return std::__invoke(*_M_parent->_M_fun, __iters[iter_difference_t<_Is>(__n)]...);
+ return _M_fun._M_call_subscript(__n, __iters...);
}, _M_inner._M_current);
}
@@ -5259,17 +5434,17 @@ namespace views::__adaptor
friend constexpr _Iterator
operator+(const _Iterator& __i, difference_type __n)
requires random_access_range<_Base<_Const>>
- { return _Iterator(*__i._M_parent, __i._M_inner + __n); }
+ { return _Iterator(__i._M_fun, __i._M_inner + __n); }
friend constexpr _Iterator
operator+(difference_type __n, const _Iterator& __i)
requires random_access_range<_Base<_Const>>
- { return _Iterator(*__i._M_parent, __i._M_inner + __n); }
+ { return _Iterator(__i._M_fun, __i._M_inner + __n); }
friend constexpr _Iterator
operator-(const _Iterator& __i, difference_type __n)
requires random_access_range<_Base<_Const>>
- { return _Iterator(*__i._M_parent, __i._M_inner - __n); }
+ { return _Iterator(__i._M_fun, __i._M_inner - __n); }
friend constexpr difference_type
operator-(const _Iterator& __x, const _Iterator& __y)
@@ -5336,7 +5511,7 @@ namespace views::__adaptor
requires move_constructible<decay_t<_Fp>> && regular_invocable<decay_t<_Fp>&>
&& is_object_v<decay_t<invoke_result_t<decay_t<_Fp>&>>>
constexpr auto
- operator() [[nodiscard]] (_Fp&& __f) const
+ operator() [[nodiscard]] (_Fp&&) const
{
return views::empty<decay_t<invoke_result_t<decay_t<_Fp>&>>>;
}
@@ -5438,7 +5613,7 @@ namespace views::__adaptor
{
// Yields tuple<_Tp, ..., _Tp> with _Nm elements.
template<typename _Tp, size_t _Nm>
- using __repeated_tuple = decltype(std::tuple_cat(std::declval<array<_Tp, _Nm>>()));
+ using __repeated_tuple = typename __make_tuple<array<_Tp, _Nm>>::__type;
// For a functor F that is callable with N arguments, the expression
// declval<__unarize<F, N>>(x) is equivalent to declval<F>(x, ..., x).
@@ -5515,9 +5690,7 @@ namespace views::__adaptor
public:
using iterator_category = input_iterator_tag;
using iterator_concept = decltype(_S_iter_concept());
- using value_type = conditional_t<_Nm == 2,
- pair<range_value_t<_Base>, range_value_t<_Base>>,
- __detail::__repeated_tuple<range_value_t<_Base>, _Nm>>;
+ using value_type = __detail::__repeated_tuple<range_value_t<_Base>, _Nm>;
using difference_type = range_difference_t<_Base>;
_Iterator() = default;
@@ -5838,13 +6011,23 @@ namespace views::__adaptor
{
using _Parent = __detail::__maybe_const_t<_Const, adjacent_transform_view>;
using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+ using _Fun_handle = decltype([]<size_t... _Ids>(std::index_sequence<_Ids...>) {
+ return __detail::__func_handle_t<
+ __detail::__maybe_const_t<_Const, _Fp>,
+ iterator_t<__detail::__maybe_const_t<(_Ids, _Const), _Vp>>...>();
+ }(make_index_sequence<_Nm>()));
- _Parent* _M_parent = nullptr;
+ [[no_unique_address]] _Fun_handle _M_fun;
_InnerIter<_Const> _M_inner;
constexpr
+ _Iterator(_Fun_handle __fun, _InnerIter<_Const> __inner)
+ : _M_fun(__fun), _M_inner(std::move(__inner))
+ { }
+
+ constexpr
_Iterator(_Parent& __parent, _InnerIter<_Const> __inner)
- : _M_parent(std::__addressof(__parent)), _M_inner(std::move(__inner))
+ : _M_fun(*__parent._M_fun), _M_inner(std::move(__inner))
{ }
static auto
@@ -5885,14 +6068,14 @@ namespace views::__adaptor
constexpr
_Iterator(_Iterator<!_Const> __i)
requires _Const && convertible_to<_InnerIter<false>, _InnerIter<_Const>>
- : _M_parent(__i._M_parent), _M_inner(std::move(__i._M_inner))
+ : _M_fun(__i._M_fun), _M_inner(std::move(__i._M_inner))
{ }
constexpr decltype(auto)
operator*() const
{
return std::apply([&](const auto&... __iters) -> decltype(auto) {
- return std::__invoke(*_M_parent->_M_fun, *__iters...);
+ return _M_fun._M_call_deref(__iters...);
}, _M_inner._M_current);
}
@@ -5944,7 +6127,7 @@ namespace views::__adaptor
operator[](difference_type __n) const requires random_access_range<_Base>
{
return std::apply([&](const auto&... __iters) -> decltype(auto) {
- return std::__invoke(*_M_parent->_M_fun, __iters[__n]...);
+ return _M_fun._M_call_subscript(__n, __iters...);
}, _M_inner._M_current);
}
@@ -5981,17 +6164,17 @@ namespace views::__adaptor
friend constexpr _Iterator
operator+(const _Iterator& __i, difference_type __n)
requires random_access_range<_Base>
- { return _Iterator(*__i._M_parent, __i._M_inner + __n); }
+ { return _Iterator(__i._M_fun, __i._M_inner + __n); }
friend constexpr _Iterator
operator+(difference_type __n, const _Iterator& __i)
requires random_access_range<_Base>
- { return _Iterator(*__i._M_parent, __i._M_inner + __n); }
+ { return _Iterator(__i._M_fun, __i._M_inner + __n); }
friend constexpr _Iterator
operator-(const _Iterator& __i, difference_type __n)
requires random_access_range<_Base>
- { return _Iterator(*__i._M_parent, __i._M_inner - __n); }
+ { return _Iterator(__i._M_fun, __i._M_inner - __n); }
friend constexpr difference_type
operator-(const _Iterator& __x, const _Iterator& __y)
@@ -6598,7 +6781,7 @@ namespace views::__adaptor
}
friend constexpr difference_type
- operator-(default_sentinel_t __y, const _Iterator& __x)
+ operator-(default_sentinel_t, const _Iterator& __x)
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
{ return __detail::__div_ceil(__x._M_end - __x._M_current, __x._M_n); }
@@ -7287,15 +7470,15 @@ namespace views::__adaptor
using iterator_category = decltype(_S_iter_cat());
};
- template<bool> struct _Iterator;
- template<bool> struct _Sentinel;
+ template<bool> class _Iterator;
+ template<bool> class _Sentinel;
public:
join_with_view() requires (default_initializable<_Vp>
&& default_initializable<_Pattern>)
= default;
- constexpr
+ constexpr explicit
join_with_view(_Vp __base, _Pattern __pattern)
: _M_base(std::move(__base)), _M_pattern(std::move(__pattern))
{ }
@@ -7303,7 +7486,7 @@ namespace views::__adaptor
template<input_range _Range>
requires constructible_from<_Vp, views::all_t<_Range>>
&& constructible_from<_Pattern, single_view<range_value_t<_InnerRange>>>
- constexpr
+ constexpr explicit
join_with_view(_Range&& __r, range_value_t<_InnerRange> __e)
: _M_base(views::all(std::forward<_Range>(__r))),
_M_pattern(views::single(std::move(__e)))
@@ -7400,7 +7583,8 @@ namespace views::__adaptor
_Parent* _M_parent = nullptr;
[[no_unique_address]]
- __detail::__maybe_present_t<forward_range<_Base>, _OuterIter> _M_outer_it;
+ __detail::__maybe_present_t<forward_range<_Base>, _OuterIter> _M_outer_it
+ = decltype(_M_outer_it)();
variant<_PatternIter, _InnerIter> _M_inner_it;
constexpr _OuterIter&
@@ -7743,7 +7927,7 @@ namespace views::__adaptor
__detail::__box<_Tp> _M_value;
[[no_unique_address]] _Bound _M_bound = _Bound();
- struct _Iterator;
+ class _Iterator;
template<typename _Range>
friend constexpr auto
@@ -8303,7 +8487,7 @@ namespace views::__adaptor
}
friend constexpr difference_type
- operator-(default_sentinel_t __y, const _Iterator& __x)
+ operator-(default_sentinel_t, const _Iterator& __x)
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
{ return __detail::__div_ceil(__x._M_end - __x._M_current, __x._M_stride); }
@@ -9354,6 +9538,10 @@ namespace views::__adaptor
return views::all(std::forward<_Range>(__r));
else if constexpr (__detail::__is_empty_view<_Tp>)
return views::empty<const element_type>;
+#if __cpp_lib_optional >= 202506L && __cpp_lib_optional_range_support // >= C++26
+ else if constexpr (__is_optional_ref_v<_Tp>)
+ return optional<const typename _Tp::value_type&>(__r);
+#endif
else if constexpr (std::__detail::__is_span<_Tp>)
return span<const element_type, _Tp::extent>(std::forward<_Range>(__r));
else if constexpr (__detail::__is_constable_ref_view<_Tp>)
@@ -9735,7 +9923,7 @@ namespace ranges
end() requires (!(__detail::__simple_view<_Vs> && ...))
{
constexpr auto __n = sizeof...(_Vs);
- if constexpr ((semiregular<iterator_t<_Vs>> && ...)
+ if constexpr (__detail::__all_forward<false, _Vs...>
&& common_range<_Vs...[__n - 1]>)
return _Iterator<false>(this, in_place_index<__n - 1>,
ranges::end(std::get<__n - 1>(_M_views)));
@@ -9747,7 +9935,7 @@ namespace ranges
end() const requires (range<const _Vs> && ...) && __detail::__concatable<const _Vs...>
{
constexpr auto __n = sizeof...(_Vs);
- if constexpr ((semiregular<iterator_t<const _Vs>> && ...)
+ if constexpr (__detail::__all_forward<true, _Vs...>
&& common_range<const _Vs...[__n - 1]>)
return _Iterator<true>(this, in_place_index<__n - 1>,
ranges::end(std::get<__n - 1>(_M_views)));
diff --git a/libstdc++-v3/include/std/regex b/libstdc++-v3/include/std/regex
index 0223066..9121d26 100644
--- a/libstdc++-v3/include/std/regex
+++ b/libstdc++-v3/include/std/regex
@@ -41,7 +41,6 @@
#include <bitset>
#include <locale>
-#include <sstream>
#include <stack>
#include <stdexcept>
#include <string>
diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore
index bec5ac3..18d0407 100644
--- a/libstdc++-v3/include/std/semaphore
+++ b/libstdc++-v3/include/std/semaphore
@@ -35,29 +35,28 @@
#include <bits/requires_hosted.h> // concurrency
-#if __cplusplus > 201703L
-#include <bits/semaphore_base.h>
-
#define __glibcxx_want_semaphore
#include <bits/version.h>
-#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && (atomic_wait || posix_sem)
+#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && atomic_wait
+#include <bits/semaphore_base.h>
+
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
- template<ptrdiff_t __least_max_value = __semaphore_impl::_S_max>
+ template<ptrdiff_t __least_max_value = _Semaphore_impl<2>::_S_max>
class counting_semaphore
{
static_assert(__least_max_value >= 0);
- static_assert(__least_max_value <= __semaphore_impl::_S_max);
- __semaphore_impl _M_sem;
+ _Semaphore_impl<__least_max_value> _M_sem;
public:
- explicit counting_semaphore(ptrdiff_t __desired) noexcept
- : _M_sem(__desired)
- { }
+ constexpr explicit
+ counting_semaphore(ptrdiff_t __desired) noexcept
+ : _M_sem(__desired)
+ { __glibcxx_assert(__desired >= 0 && __desired <= max()); }
~counting_semaphore() = default;
@@ -69,8 +68,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __least_max_value; }
void
- release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1)))
- { _M_sem._M_release(__update); }
+ release(ptrdiff_t __update = 1) noexcept
+ {
+ [[maybe_unused]] ptrdiff_t __old = _M_sem._M_release(__update);
+ __glibcxx_assert(__update >= 0 && __update <= max() - __old);
+ }
void
acquire() noexcept(noexcept(_M_sem._M_acquire()))
@@ -91,10 +93,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return _M_sem._M_try_acquire_until(__atime); }
};
+ /** @brief A binary semaphore
+ *
+ * @since C++20
+ */
using binary_semaphore = std::counting_semaphore<1>;
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
-#endif // cpp_lib_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE
#endif // __cpp_lib_semaphore
#endif // _GLIBCXX_SEMAPHORE
diff --git a/libstdc++-v3/include/std/shared_mutex b/libstdc++-v3/include/std/shared_mutex
index 94c8532..92f6227 100644
--- a/libstdc++-v3/include/std/shared_mutex
+++ b/libstdc++-v3/include/std/shared_mutex
@@ -208,10 +208,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
try_lock()
{
int __ret = __glibcxx_rwlock_trywrlock(&_M_rwlock);
- if (__ret == EBUSY) return false;
- // Errors not handled: EINVAL
+ if (__ret == 0)
+ return true;
+ if (__ret == EBUSY)
+ return false;
+ // Errors not handled: EINVAL, EDEADLK
__glibcxx_assert(__ret == 0);
- return true;
+ // try_lock() is not permitted to throw
+ return false;
}
void
@@ -520,23 +524,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
try_lock_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret = __glibcxx_rwlock_timedwrlock(&_M_rwlock, &__ts);
- // On self-deadlock, we just fail to acquire the lock. Technically,
- // the program violated the precondition.
- if (__ret == ETIMEDOUT || __ret == EDEADLK)
+ if (__ret == 0)
+ return true;
+ if (__ret == ETIMEDOUT)
return false;
- // Errors not handled: EINVAL
+ // Errors not handled: EINVAL, EDEADLK
__glibcxx_assert(__ret == 0);
- return true;
+ return false;
}
#ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK
@@ -546,24 +542,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
try_lock_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret = pthread_rwlock_clockwrlock(&_M_rwlock, CLOCK_MONOTONIC,
&__ts);
- // On self-deadlock, we just fail to acquire the lock. Technically,
- // the program violated the precondition.
- if (__ret == ETIMEDOUT || __ret == EDEADLK)
+ if (__ret == 0)
+ return true;
+ if (__ret == ETIMEDOUT)
return false;
- // Errors not handled: EINVAL
+ // Errors not handled: EINVAL, EDEADLK
__glibcxx_assert(__ret == 0);
- return true;
+ return false;
}
#endif
@@ -596,14 +584,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
try_lock_shared_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret;
// Unlike for lock(), we are not allowed to throw an exception so if
@@ -615,18 +596,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// acquire the lock even if it would be logically free; however, this
// is allowed by the standard, and we made a "strong effort"
// (see C++14 30.4.1.4p26).
- // For cases where the implementation detects a deadlock we
- // intentionally block and timeout so that an early return isn't
- // mistaken for a spurious failure, which might help users realise
- // there is a deadlock.
do
__ret = __glibcxx_rwlock_timedrdlock(&_M_rwlock, &__ts);
- while (__ret == EAGAIN || __ret == EDEADLK);
+ while (__ret == EAGAIN);
+ if (__ret == 0)
+ return true;
if (__ret == ETIMEDOUT)
return false;
- // Errors not handled: EINVAL
+ // Errors not handled: EINVAL, EDEADLK
__glibcxx_assert(__ret == 0);
- return true;
+ return false;
}
#ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK
@@ -636,24 +615,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
try_lock_shared_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
+ struct timespec __ts = chrono::__to_timeout_timespec(__atime);
int __ret = pthread_rwlock_clockrdlock(&_M_rwlock, CLOCK_MONOTONIC,
&__ts);
- // On self-deadlock, we just fail to acquire the lock. Technically,
- // the program violated the precondition.
- if (__ret == ETIMEDOUT || __ret == EDEADLK)
+ // On self-deadlock, if _GLIBCXX_ASSERTIONS is not defined, we just
+ // fail to acquire the lock. Technically, the program violated the
+ // precondition.
+ if (__ret == 0)
+ return true;
+ if (__ret == ETIMEDOUT)
return false;
- // Errors not handled: EINVAL
+ // Errors not handled: EINVAL, EDEADLK
__glibcxx_assert(__ret == 0);
- return true;
+ return false;
}
#endif
diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span
index 49ab910..5808911 100644
--- a/libstdc++-v3/include/std/span
+++ b/libstdc++-v3/include/std/span
@@ -376,7 +376,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
else
static_assert(_Count <= extent);
using _Sp = span<element_type, _Count>;
- return _Sp{ _SizedPtr{this->data()} };
+ return _Sp(_SizedPtr{this->data()});
}
[[nodiscard]]
@@ -384,7 +384,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
first(size_type __count) const noexcept
{
__glibcxx_assert(__count <= size());
- return { this->data(), __count };
+ return span<element_type>(this->data(), __count);
}
template<size_t _Count>
@@ -397,7 +397,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
else
static_assert(_Count <= extent);
using _Sp = span<element_type, _Count>;
- return _Sp{ _SizedPtr{this->data() + (this->size() - _Count)} };
+ return _Sp(_SizedPtr{this->data() + (this->size() - _Count)});
}
[[nodiscard]]
@@ -405,7 +405,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
last(size_type __count) const noexcept
{
__glibcxx_assert(__count <= size());
- return { this->data() + (this->size() - __count), __count };
+ return span<element_type>(this->data() + (this->size() - __count),
+ __count);
}
template<size_t _Offset, size_t _Count = dynamic_extent>
@@ -424,7 +425,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using _Sp = span<element_type, _S_subspan_extent<_Offset, _Count>()>;
if constexpr (_Count == dynamic_extent)
- return _Sp{ this->data() + _Offset, this->size() - _Offset };
+ return _Sp(this->data() + _Offset, this->size() - _Offset);
else
{
if constexpr (_Extent == dynamic_extent)
@@ -437,7 +438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static_assert(_Count <= extent);
static_assert(_Count <= (extent - _Offset));
}
- return _Sp{ _SizedPtr{this->data() + _Offset} };
+ return _Sp(_SizedPtr{this->data() + _Offset});
}
}
@@ -454,7 +455,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__glibcxx_assert(__count <= size());
__glibcxx_assert(__offset + __count <= size());
}
- return {this->data() + __offset, __count};
+ return span<element_type>(this->data() + __offset, __count);
}
private:
@@ -476,6 +477,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
};
// deduction guides
+ namespace __detail
+ {
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4351. integral-constant-like needs more remove_cvref_t
+ template<typename _Tp>
+ concept __integral_constant_like =
+ is_integral_v<remove_cvref_t<decltype(_Tp::value)>>
+ && !is_same_v<bool, remove_cvref_t<decltype(_Tp::value)>>
+ && convertible_to<_Tp, decltype(_Tp::value)>
+ && equality_comparable_with<_Tp, decltype(_Tp::value)>
+ && bool_constant<_Tp() == _Tp::value>::value
+ && bool_constant<static_cast<decltype(_Tp::value)>(_Tp()) == _Tp::value>
+ ::value;
+
+ template<typename _Tp>
+ constexpr size_t __maybe_static_ext = dynamic_extent;
+
+ template<__integral_constant_like _Tp>
+ constexpr size_t __maybe_static_ext<_Tp> = {_Tp::value};
+ }
template<typename _Type, size_t _ArrayExtent>
span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>;
@@ -489,7 +510,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<contiguous_iterator _Iter, typename _End>
span(_Iter, _End)
- -> span<remove_reference_t<iter_reference_t<_Iter>>>;
+ -> span<remove_reference_t<iter_reference_t<_Iter>>,
+ __detail::__maybe_static_ext<_End>>;
template<ranges::contiguous_range _Range>
span(_Range &&)
diff --git a/libstdc++-v3/include/std/spanstream b/libstdc++-v3/include/std/spanstream
index 23a340a..fbb40ff 100644
--- a/libstdc++-v3/include/std/spanstream
+++ b/libstdc++-v3/include/std/spanstream
@@ -152,7 +152,7 @@ template<typename _CharT, typename _Traits>
if (__way == ios_base::beg)
{
- if (0 <= __off && __off <= _M_buf.size())
+ if (0 <= __off && (size_t)__off <= _M_buf.size())
{
if (__which & ios_base::in)
this->setg(this->eback(), this->eback() + __off, this->egptr());
@@ -188,7 +188,7 @@ template<typename _CharT, typename _Traits>
if (__builtin_add_overflow(__base, __off, &__off)) [[unlikely]]
return __ret;
- if (__off < 0 || __off > _M_buf.size()) [[unlikely]]
+ if (__off < 0 || (size_t)__off > _M_buf.size()) [[unlikely]]
return __ret;
if (__which & ios_base::in)
diff --git a/libstdc++-v3/include/std/sstream b/libstdc++-v3/include/std/sstream
index ad0c16a..b1b4126 100644
--- a/libstdc++-v3/include/std/sstream
+++ b/libstdc++-v3/include/std/sstream
@@ -41,8 +41,16 @@
#include <istream>
#include <ostream>
+
#include <bits/alloc_traits.h> // allocator_traits, __allocator_like
+#define __glibcxx_want_sstream_from_string_view
+#include <bits/version.h>
+
+#ifdef __cpp_lib_sstream_from_string_view
+# include <string_view>
+#endif
+
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
# define _GLIBCXX_LVAL_REF_QUAL &
# define _GLIBCXX_SSTREAM_ALWAYS_INLINE
@@ -52,8 +60,6 @@
# define _GLIBCXX_SSTREAM_ALWAYS_INLINE [[__gnu__::__always_inline__]]
#endif
-
-
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -159,6 +165,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{ __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0); }
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
+ // P0408 Efficient access to basic_stringbuf buffer
explicit
basic_stringbuf(const allocator_type& __a)
: basic_stringbuf(ios_base::in | std::ios_base::out, __a)
@@ -197,7 +204,36 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
| ios_base::out)
: basic_stringbuf(__s, __mode, allocator_type{})
{ }
+#endif
+#ifdef __cpp_lib_sstream_from_string_view
+ template<typename _Tp>
+ explicit
+ basic_stringbuf(const _Tp& __t,
+ ios_base::openmode __mode = ios_base::in | ios_base::out)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : basic_stringbuf(__t, __mode, allocator_type{})
+ { }
+
+ template<typename _Tp>
+ basic_stringbuf(const _Tp& __t, const allocator_type& __a)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : basic_stringbuf(__t, ios_base::in | ios_base::out, __a)
+ { }
+
+ template<typename _Tp>
+ basic_stringbuf(const _Tp& __t, ios_base::openmode __mode,
+ const allocator_type& __a)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : _M_string(__t, __a)
+ { _M_stringbuf_init(__mode); }
+#endif // C++26
+
+#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
+ // P0408 Efficient access to basic_stringbuf buffer
basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a)
: basic_stringbuf(std::move(__rhs), __a, __xfer_bufptrs(__rhs, this))
{ __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0); }
@@ -262,6 +298,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
#if __cplusplus > 201703L
#if _GLIBCXX_USE_CXX11_ABI
#if __cpp_concepts
+ // P0407 Allocator-aware basic_streambuf
template<__allocator_like _SAlloc>
_GLIBCXX_NODISCARD
basic_string<_CharT, _Traits, _SAlloc>
@@ -317,6 +354,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
#if __cpp_concepts
+ // P0407 Allocator-aware basic_streambuf
template<__allocator_like _SAlloc>
requires (!is_same_v<_SAlloc, _Alloc>)
void
@@ -335,6 +373,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
}
#endif
+#ifdef __cpp_lib_sstream_from_string_view
+ template <typename _Tp>
+ void
+ str(const _Tp& __t)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ {
+ basic_string_view<_CharT, _Traits> __sv{__t};
+ _M_string = __sv;
+ _M_stringbuf_init(_M_mode);
+ }
+#endif // C++26
+
protected:
// Common initialization code goes here.
void
@@ -521,6 +572,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{ }
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
+ // P0408 Efficient access to basic_stringbuf buffer
+
// The move constructor initializes an __xfer_bufptrs temporary then
// delegates to this constructor to performs moves during its lifetime.
basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a,
@@ -584,7 +637,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
*/
basic_istringstream()
: __istream_type(), _M_stringbuf(ios_base::in)
- { this->init(&_M_stringbuf); }
+ { this->init(std::__addressof(_M_stringbuf)); }
/**
* @brief Starts with an empty string buffer.
@@ -601,7 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
explicit
basic_istringstream(ios_base::openmode __mode)
: __istream_type(), _M_stringbuf(__mode | ios_base::in)
- { this->init(&_M_stringbuf); }
+ { this->init(std::__addressof(_M_stringbuf)); }
/**
* @brief Starts with an existing string buffer.
@@ -620,7 +673,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
basic_istringstream(const __string_type& __str,
ios_base::openmode __mode = ios_base::in)
: __istream_type(), _M_stringbuf(__str, __mode | ios_base::in)
- { this->init(&_M_stringbuf); }
+ { this->init(std::__addressof(_M_stringbuf)); }
/**
* @brief The destructor does nothing.
@@ -637,9 +690,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
basic_istringstream(basic_istringstream&& __rhs)
: __istream_type(std::move(__rhs)),
_M_stringbuf(std::move(__rhs._M_stringbuf))
- { __istream_type::set_rdbuf(&_M_stringbuf); }
+ { __istream_type::set_rdbuf(std::__addressof(_M_stringbuf)); }
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
+ // P0408 Efficient access to basic_stringbuf buffer
basic_istringstream(ios_base::openmode __mode, const allocator_type& __a)
: __istream_type(), _M_stringbuf(__mode | ios_base::in, __a)
{ this->init(std::__addressof(_M_stringbuf)); }
@@ -671,6 +725,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{ }
#endif // C++20
+#ifdef __cpp_lib_sstream_from_string_view
+ template <typename _Tp>
+ explicit
+ basic_istringstream(const _Tp& __t,
+ ios_base::openmode __mode = ios_base::in)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : basic_istringstream(__t, __mode, allocator_type{})
+ { }
+
+ template <typename _Tp>
+ basic_istringstream(const _Tp& __t, const allocator_type& __a)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : basic_istringstream(__t, ios_base::in, __a)
+ { }
+
+ template <typename _Tp>
+ basic_istringstream(const _Tp& __t, ios_base::openmode __mode,
+ const allocator_type& __a)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : __istream_type(), _M_stringbuf(__t, __mode | ios_base::in, __a)
+ { this->init(std::__addressof(_M_stringbuf)); }
+#endif // C++26
+
// 27.8.3.2 Assign and swap:
basic_istringstream&
@@ -702,7 +782,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_GLIBCXX_NODISCARD
__stringbuf_type*
rdbuf() const
- { return const_cast<__stringbuf_type*>(&_M_stringbuf); }
+ { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); }
/**
* @brief Copying out the string buffer.
@@ -716,6 +796,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
#if __cplusplus > 201703L
#if _GLIBCXX_USE_CXX11_ABI
#if __cpp_concepts
+ // P0407 Allocator-aware basic_streambuf
template<__allocator_like _SAlloc>
_GLIBCXX_NODISCARD
basic_string<_CharT, _Traits, _SAlloc>
@@ -747,6 +828,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
#if __cpp_concepts
+ // P0407 Allocator-aware basic_streambuf
template<__allocator_like _SAlloc>
requires (!is_same_v<_SAlloc, _Alloc>)
void
@@ -758,6 +840,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
str(__string_type&& __s)
{ _M_stringbuf.str(std::move(__s)); }
#endif
+
+#ifdef __cpp_lib_sstream_from_string_view
+ template<typename _Tp>
+ void
+ str(const _Tp& __t)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ { _M_stringbuf.str(__t); }
+#endif // C++26
};
@@ -812,7 +903,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
*/
basic_ostringstream()
: __ostream_type(), _M_stringbuf(ios_base::out)
- { this->init(&_M_stringbuf); }
+ { this->init(std::__addressof(_M_stringbuf)); }
/**
* @brief Starts with an empty string buffer.
@@ -829,7 +920,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
explicit
basic_ostringstream(ios_base::openmode __mode)
: __ostream_type(), _M_stringbuf(__mode | ios_base::out)
- { this->init(&_M_stringbuf); }
+ { this->init(std::__addressof(_M_stringbuf)); }
/**
* @brief Starts with an existing string buffer.
@@ -848,7 +939,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
basic_ostringstream(const __string_type& __str,
ios_base::openmode __mode = ios_base::out)
: __ostream_type(), _M_stringbuf(__str, __mode | ios_base::out)
- { this->init(&_M_stringbuf); }
+ { this->init(std::__addressof(_M_stringbuf)); }
/**
* @brief The destructor does nothing.
@@ -865,9 +956,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
basic_ostringstream(basic_ostringstream&& __rhs)
: __ostream_type(std::move(__rhs)),
_M_stringbuf(std::move(__rhs._M_stringbuf))
- { __ostream_type::set_rdbuf(&_M_stringbuf); }
+ { __ostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); }
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
+ // P0408 Efficient access to basic_stringbuf buffer
basic_ostringstream(ios_base::openmode __mode, const allocator_type& __a)
: __ostream_type(), _M_stringbuf(__mode | ios_base::out, __a)
{ this->init(std::__addressof(_M_stringbuf)); }
@@ -899,6 +991,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{ }
#endif // C++20
+#ifdef __cpp_lib_sstream_from_string_view
+ template <typename _Tp>
+ explicit
+ basic_ostringstream(
+ const _Tp& __t, ios_base::openmode __mode = ios_base::out)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : basic_ostringstream(__t, __mode, allocator_type{})
+ { }
+
+ template <typename _Tp>
+ basic_ostringstream(const _Tp& __t, const allocator_type& __a)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : basic_ostringstream(__t, ios_base::out, __a)
+ { }
+
+ template <typename _Tp>
+ basic_ostringstream(const _Tp& __t, ios_base::openmode __mode,
+ const allocator_type& __a)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : __ostream_type(), _M_stringbuf(__t, __mode | ios_base::out, __a)
+ { this->init(std::__addressof(_M_stringbuf)); }
+#endif // C++26
+
// 27.8.3.2 Assign and swap:
basic_ostringstream&
@@ -930,7 +1048,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_GLIBCXX_NODISCARD
__stringbuf_type*
rdbuf() const
- { return const_cast<__stringbuf_type*>(&_M_stringbuf); }
+ { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); }
/**
* @brief Copying out the string buffer.
@@ -944,6 +1062,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
#if __cplusplus > 201703L
#if _GLIBCXX_USE_CXX11_ABI
#if __cpp_concepts
+ // P0407 Allocator-aware basic_streambuf
template<__allocator_like _SAlloc>
_GLIBCXX_NODISCARD
basic_string<_CharT, _Traits, _SAlloc>
@@ -975,6 +1094,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
#if __cpp_concepts
+ // P0407 Allocator-aware basic_streambuf
template<__allocator_like _SAlloc>
requires (!is_same_v<_SAlloc, _Alloc>)
void
@@ -986,6 +1106,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
str(__string_type&& __s)
{ _M_stringbuf.str(std::move(__s)); }
#endif
+
+#ifdef __cpp_lib_sstream_from_string_view
+ template<typename _Tp>
+ void
+ str(const _Tp& __t)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ { _M_stringbuf.str(__t); }
+#endif // C++26
};
@@ -1040,7 +1169,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
*/
basic_stringstream()
: __iostream_type(), _M_stringbuf(ios_base::out | ios_base::in)
- { this->init(&_M_stringbuf); }
+ { this->init(std::__addressof(_M_stringbuf)); }
/**
* @brief Starts with an empty string buffer.
@@ -1055,7 +1184,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
explicit
basic_stringstream(ios_base::openmode __m)
: __iostream_type(), _M_stringbuf(__m)
- { this->init(&_M_stringbuf); }
+ { this->init(std::__addressof(_M_stringbuf)); }
/**
* @brief Starts with an existing string buffer.
@@ -1072,7 +1201,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
basic_stringstream(const __string_type& __str,
ios_base::openmode __m = ios_base::out | ios_base::in)
: __iostream_type(), _M_stringbuf(__str, __m)
- { this->init(&_M_stringbuf); }
+ { this->init(std::__addressof(_M_stringbuf)); }
/**
* @brief The destructor does nothing.
@@ -1089,12 +1218,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
basic_stringstream(basic_stringstream&& __rhs)
: __iostream_type(std::move(__rhs)),
_M_stringbuf(std::move(__rhs._M_stringbuf))
- { __iostream_type::set_rdbuf(&_M_stringbuf); }
+ { __iostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); }
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
+ // P0408 Efficient access to basic_stringbuf buffer
basic_stringstream(ios_base::openmode __mode, const allocator_type& __a)
: __iostream_type(), _M_stringbuf(__mode, __a)
- { this->init(&_M_stringbuf); }
+ { this->init(std::__addressof(_M_stringbuf)); }
explicit
basic_stringstream(__string_type&& __str,
@@ -1125,6 +1255,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{ }
#endif // C++20
+#ifdef __cpp_lib_sstream_from_string_view
+ template <typename _Tp>
+ explicit
+ basic_stringstream(const _Tp& __t,
+ ios_base::openmode __mode = ios_base::in | ios_base::out)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : basic_stringstream(__t, __mode, allocator_type{})
+ { }
+
+ template <typename _Tp>
+ basic_stringstream(const _Tp& __t, const allocator_type& __a)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ : basic_stringstream(__t, ios_base::in | ios_base::out, __a)
+ { }
+
+ template <typename _Tp>
+ basic_stringstream(const _Tp& __t, ios_base::openmode __mode,
+ const allocator_type& __a)
+ requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>)
+ : __iostream_type(), _M_stringbuf(__t, __mode, __a)
+ { this->init(std::__addressof(_M_stringbuf)); }
+#endif // C++26
+
// 27.8.3.2 Assign and swap:
basic_stringstream&
@@ -1156,7 +1311,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_GLIBCXX_NODISCARD
__stringbuf_type*
rdbuf() const
- { return const_cast<__stringbuf_type*>(&_M_stringbuf); }
+ { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); }
/**
* @brief Copying out the string buffer.
@@ -1170,6 +1325,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
#if __cplusplus > 201703L
#if _GLIBCXX_USE_CXX11_ABI
#if __cpp_concepts
+ // P0407 Allocator-aware basic_streambuf
template<__allocator_like _SAlloc>
_GLIBCXX_NODISCARD
basic_string<_CharT, _Traits, _SAlloc>
@@ -1201,6 +1357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
#if __cpp_concepts
+ // P0407 Allocator-aware basic_streambuf
template<__allocator_like _SAlloc>
requires (!is_same_v<_SAlloc, _Alloc>)
void
@@ -1212,6 +1369,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
str(__string_type&& __s)
{ _M_stringbuf.str(std::move(__s)); }
#endif
+
+#ifdef __cpp_lib_sstream_from_string_view
+ template<typename _Tp>
+ void
+ str(const _Tp& __t)
+ requires (is_convertible_v<const _Tp&,
+ basic_string_view<_CharT, _Traits>>)
+ { _M_stringbuf.str(__t); }
+#endif // C++26
};
#if __cplusplus >= 201103L
diff --git a/libstdc++-v3/include/std/stack b/libstdc++-v3/include/std/stack
index 5cea476..507b974 100644
--- a/libstdc++-v3/include/std/stack
+++ b/libstdc++-v3/include/std/stack
@@ -61,11 +61,61 @@
#include <bits/requires_hosted.h> // containers
-#include <deque>
-#include <bits/stl_stack.h>
-
#define __glibcxx_want_adaptor_iterator_pair_constructor
#define __glibcxx_want_containers_ranges
#include <bits/version.h>
+#include <deque>
+#include <bits/stl_stack.h>
+
+#ifdef __glibcxx_format_ranges // C++ >= 23 && HOSTED
+#include <bits/formatfwd.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ // Standard does not constrain accepted _CharT, we do so we can
+ // befriend specializations.
+ template<__format::__char _CharT, typename _Tp,
+ formattable<_CharT> _Container>
+ struct formatter<stack<_Tp, _Container>, _CharT>
+ {
+ private:
+ using __maybe_const_adaptor
+ = __conditional_t<
+ __format::__const_formattable_range<_Container, _CharT>,
+ const stack<_Tp, _Container>, stack<_Tp, _Container>>;
+
+ public:
+ // Standard declares this as template accepting unconstrained
+ // ParseContext type.
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ { return _M_f.parse(__pc); }
+
+ // Standard declares this as template accepting unconstrained
+ // FormatContext type.
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__maybe_const_adaptor& __a,
+ basic_format_context<_Out, _CharT>& __fc) const
+ { return _M_f.format(__a.c, __fc); }
+
+ private:
+ // Standard uses formatter<ref_view<_Container>, _CharT>.
+ range_formatter<_Tp, _CharT> _M_f;
+ };
+
+#if __glibcxx_print >= 202406L
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4398. enable_nonlocking_formatter_optimization should be disabled for container adaptors
+ template<typename _Tp, typename _Container>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<stack<_Tp, _Container>> = false;
+#endif
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // __glibcxx_format_ranges
+
+
#endif /* _GLIBCXX_STACK */
diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace
index 4911222..587a163 100644
--- a/libstdc++-v3/include/std/stacktrace
+++ b/libstdc++-v3/include/std/stacktrace
@@ -208,6 +208,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
if (_S_current(__cb, std::__addressof(__ret)))
__ret._M_clear();
+ else
+ __ret._M_trim();
}
return __ret;
}
@@ -224,6 +226,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
if (_S_current(__cb, std::__addressof(__ret), __skip))
__ret._M_clear();
+ else
+ __ret._M_trim();
}
return __ret;
@@ -260,6 +264,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
}
}
+ else
+ __ret._M_trim();
}
return __ret;
}
@@ -651,6 +657,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
};
+ void
+ _M_trim() noexcept
+ {
+ // libbacktrace adds an invalid -1UL entry at the end, remove it.
+ if (!empty() && !end()[-1])
+ _M_impl._M_resize(size() - 1, _M_alloc);
+ }
+
[[no_unique_address]] allocator_type _M_alloc{};
_Impl _M_impl{};
@@ -669,13 +683,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline ostream&
operator<<(ostream& __os, const stacktrace_entry& __f)
{
+ if (!__f) [[unlikely]]
+ return __os << "<unknown>";
+
string __desc, __file;
int __line;
- if (__f._M_get_info(&__desc, &__file, &__line))
+ if (__f._M_get_info(&__desc, &__file, &__line)) [[likely]]
{
- __os.width(4);
- __os << __desc << " at " << __file << ':' << __line;
+ __os << ' ';
+ if (__desc.empty()) [[unlikely]]
+ __os << "<unknown>";
+ else
+ __os << __desc;
+ if (!__file.empty()) [[likely]]
+ __os << " at " << __file << ':' << __line;
}
+
+ struct _Flag_guard // Set and restore hex format
+ {
+ _Flag_guard(ios& __s) : _M_ios(__s) { }
+ ~_Flag_guard() { _M_ios.setf(_M_f); }
+
+ ios& _M_ios;
+ ios::fmtflags _M_f = _M_ios.setf(ios::hex, ios::basefield);
+ };
+ _Flag_guard __g(__os);
+ __os << " [0x" << __f.native_handle() << ']';
return __os;
}
@@ -683,7 +716,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline ostream&
operator<<(ostream& __os, const basic_stacktrace<_Allocator>& __st)
{
- for (stacktrace::size_type __i = 0; __i < __st.size(); ++__i)
+ using size_type = typename basic_stacktrace<_Allocator>::size_type;
+ for (size_type __i = 0, __size = __st.size(); __i < __size; ++__i)
{
__os.width(4);
__os << __i << "# " << __st[__i] << '\n';
@@ -765,6 +799,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__format::_Spec<char> _M_spec;
};
+#if __glibcxx_print >= 202406L
+ template<>
+ inline constexpr bool
+ enable_nonlocking_formatter_optimization<stacktrace_entry> = true;
+#endif
+
template<typename _Allocator>
class formatter<basic_stacktrace<_Allocator>>
{
@@ -790,6 +830,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
};
+#if __glibcxx_print >= 202406L
+ template<typename _Allocator>
+ constexpr bool
+ enable_nonlocking_formatter_optimization<basic_stacktrace<_Allocator>> = true;
+#endif
+
namespace pmr
{
using stacktrace
diff --git a/libstdc++-v3/include/std/stop_token b/libstdc++-v3/include/std/stop_token
index 1225b3a..b593daf 100644
--- a/libstdc++-v3/include/std/stop_token
+++ b/libstdc++-v3/include/std/stop_token
@@ -34,8 +34,7 @@
#define __glibcxx_want_jthread
#include <bits/version.h>
-#if __cplusplus > 201703L
-
+#ifdef __glibcxx_jthread // C++ >= 20
#include <atomic>
#include <bits/std_thread.h>
@@ -649,7 +648,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Callback>
stop_callback(stop_token, _Callback) -> stop_callback<_Callback>;
+ /// @cond undocumented
+ namespace __detail::__variant
+ {
+ template<typename> struct _Never_valueless_alt; // see <variant>
+
+ // Provide the strong exception-safety guarantee when emplacing a
+ // stop_token or stop_source into a variant.
+ template<>
+ struct _Never_valueless_alt<std::stop_token>
+ : true_type
+ { };
+
+ template<>
+ struct _Never_valueless_alt<std::stop_source>
+ : true_type
+ { };
+ } // namespace __detail::__variant
+ /// @endcond
+
_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace
-#endif // __cplusplus > 201703L
+} // namespace std
+#endif // __glibcxx_jthread
#endif // _GLIBCXX_STOP_TOKEN
diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string
index 7186471..918b415 100644
--- a/libstdc++-v3/include/std/string
+++ b/libstdc++-v3/include/std/string
@@ -51,7 +51,6 @@
#include <bits/stl_function.h> // For less
#include <ext/numeric_traits.h>
#include <bits/stl_algobase.h>
-#include <bits/refwrap.h>
#include <bits/range_access.h>
#include <bits/basic_string.h>
#include <bits/basic_string.tcc>
@@ -64,6 +63,7 @@
#define __glibcxx_want_erase_if
#define __glibcxx_want_nonmember_container_access
#define __glibcxx_want_string_resize_and_overwrite
+#define __glibcxx_want_string_subview
#define __glibcxx_want_string_udls
#define __glibcxx_want_to_string
#include <bits/version.h>
@@ -96,33 +96,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _CharT, typename _Traits, typename _Alloc,
typename _Predicate>
- _GLIBCXX20_CONSTEXPR
- inline typename basic_string<_CharT, _Traits, _Alloc>::size_type
+ constexpr typename basic_string<_CharT, _Traits, _Alloc>::size_type
erase_if(basic_string<_CharT, _Traits, _Alloc>& __cont, _Predicate __pred)
{
using namespace __gnu_cxx;
const auto __osz = __cont.size();
const auto __end = __cont.end();
auto __removed = std::__remove_if(__cont.begin(), __end,
- __ops::__pred_iter(std::ref(__pred)));
+ std::move(__pred));
__cont.erase(__removed, __end);
return __osz - __cont.size();
}
template<typename _CharT, typename _Traits, typename _Alloc,
typename _Up _GLIBCXX26_DEF_VAL_T(_CharT)>
- _GLIBCXX20_CONSTEXPR
- inline typename basic_string<_CharT, _Traits, _Alloc>::size_type
+ constexpr typename basic_string<_CharT, _Traits, _Alloc>::size_type
erase(basic_string<_CharT, _Traits, _Alloc>& __cont, const _Up& __value)
- {
- using namespace __gnu_cxx;
- const auto __osz = __cont.size();
- const auto __end = __cont.end();
- auto __removed = std::__remove_if(__cont.begin(), __end,
- __ops::__iter_equals_val(__value));
- __cont.erase(__removed, __end);
- return __osz - __cont.size();
- }
+ { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); }
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // __cpp_lib_erase_if
diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index 842f6ad..b226544 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -40,9 +40,10 @@
#define __glibcxx_want_constexpr_char_traits
#define __glibcxx_want_constexpr_string_view
#define __glibcxx_want_freestanding_string_view
-#define __glibcxx_want_string_view
#define __glibcxx_want_starts_ends_with
#define __glibcxx_want_string_contains
+#define __glibcxx_want_string_subview
+#define __glibcxx_want_string_view
#include <bits/version.h>
#if __cplusplus >= 201703L
@@ -342,6 +343,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return basic_string_view{_M_str + __pos, __rlen};
}
+#ifdef __glibcxx_string_subview // >= C++26
+ [[nodiscard]]
+ constexpr basic_string_view
+ subview(size_type __pos = 0, size_type __n = npos) const
+ { return substr(__pos, __n); }
+#endif
+
[[nodiscard]]
constexpr int
compare(basic_string_view __str) const noexcept
diff --git a/libstdc++-v3/include/std/syncstream b/libstdc++-v3/include/std/syncstream
index e2b5a19..1e17597 100644
--- a/libstdc++-v3/include/std/syncstream
+++ b/libstdc++-v3/include/std/syncstream
@@ -46,7 +46,6 @@
#include <bits/alloc_traits.h>
#include <bits/allocator.h>
#include <bits/functexcept.h>
-#include <bits/functional_hash.h>
#include <bits/std_mutex.h>
namespace std _GLIBCXX_VISIBILITY(default)
@@ -199,11 +198,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __mutex
{
#if _GLIBCXX_HAS_GTHREADS
- mutex* _M_mtx;
+ mutex* _M_mtx = nullptr;
- __mutex(void* __t)
- : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr)
- { }
+ __mutex(void* __t) // __t is the underlying sbuf, as hash seed.
+ {
+ extern mutex& __syncbuf_get_mutex(void*); // in src/c++20/syncbuf.cc
+ if (__t) _M_mtx = &__syncbuf_get_mutex(__t);
+ }
void
swap(__mutex& __other) noexcept
@@ -220,17 +221,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
_M_mtx->unlock();
}
-
- // FIXME: This should be put in the .so
- static mutex&
- _S_get_mutex(void* __t)
- {
- const unsigned char __mask = 0xf;
- static mutex __m[__mask + 1];
-
- auto __key = _Hash_impl::hash(__t) & __mask;
- return __m[__key];
- }
#else
__mutex(void*) { }
void swap(__mutex&&) noexcept { }
diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread
index d2f91ad..ccab1e4 100644
--- a/libstdc++-v3/include/std/thread
+++ b/libstdc++-v3/include/std/thread
@@ -294,10 +294,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
stop_source _M_stop_source;
thread _M_thread;
};
+
+ /// @cond undocumented
+ namespace __detail::__variant
+ {
+ template<typename> struct _Never_valueless_alt; // see <variant>
+
+ // Provide the strong exception-safety guarantee when emplacing a
+ // jthread into a variant.
+ template<>
+ struct _Never_valueless_alt<std::jthread>
+ : true_type
+ { };
+ } // namespace __detail::__variant
+ /// @endcond
#endif // __cpp_lib_jthread
#ifdef __cpp_lib_formatters // C++ >= 23
- template<typename _CharT>
+ // We deviate from the standard, that does not put requirements
+ // on _CharT here.
+ template<__format::__char _CharT>
requires is_pointer_v<thread::native_handle_type>
|| is_integral_v<thread::native_handle_type>
class formatter<thread::id, _CharT>
@@ -307,6 +323,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
parse(basic_format_parse_context<_CharT>& __pc)
{
__format::_Spec<_CharT> __spec{};
+ __spec._M_align = __format::_Align_right;
const auto __last = __pc.end();
auto __first = __pc.begin();
@@ -334,41 +351,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__finished())
return __first;
- __throw_format_error("format error: invalid format-spec for "
- "std::thread::id");
+ std::__throw_format_error("format error: invalid format-spec for "
+ "std::thread::id");
}
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(thread::id __id, basic_format_context<_Out, _CharT>& __fc) const
{
- basic_string_view<_CharT> __sv;
- if constexpr (is_same_v<_CharT, char>)
- __sv = "{}thread::id of a non-executing thread";
- else
- __sv = L"{}thread::id of a non-executing thread";
- basic_string<_CharT> __str;
+
if (__id == thread::id())
- __sv.remove_prefix(2);
- else
{
- using _FmtStr = __format::_Runtime_format_string<_CharT>;
- // Convert non-void pointers to const void* for formatted output.
- using __output_type
- = __conditional_t<is_pointer_v<thread::native_handle_type>,
- const void*,
- thread::native_handle_type>;
- auto __o = static_cast<__output_type>(__id._M_thread);
- __sv = __str = std::format(_FmtStr(__sv.substr(0, 2)), __o);
+ const _CharT* __msg;
+ if constexpr (is_same_v<_CharT, char>)
+ __msg = "thread::id of a non-executing thread";
+ else
+ __msg = L"thread::id of a non-executing thread";
+
+ __format::__formatter_str<_CharT> __formatter(_M_spec);
+ return __formatter.format(__msg, __fc);
}
- return __format::__write_padded_as_spec(__sv, __sv.size(),
- __fc, _M_spec,
- __format::_Align_right);
+
+ using _HandleFormatter
+ = __conditional_t<is_pointer_v<thread::native_handle_type>,
+ __format::__formatter_ptr<_CharT>,
+ __format::__formatter_int<_CharT>>;
+
+ _HandleFormatter __formatter(_M_spec);
+ return __formatter.format(__id._M_thread, __fc);
}
private:
__format::_Spec<_CharT> _M_spec;
};
+
+#if __glibcxx_print >= 202406L
+ template<>
+ inline constexpr bool
+ enable_nonlocking_formatter_optimization<thread::id> = true;
+#endif
+
#endif // __cpp_lib_formatters
/// @} group threads
diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index 2e69af1..d4db125 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -1984,14 +1984,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
class tuple<>
{
public:
+ // We need the default since we're going to define no-op
+ // allocator constructors.
+ tuple() = default;
+ // Defaulted copy operations to maintain trivial copyability.
+ // and support non-const assignment expressions.
+ tuple(const tuple&) = default;
+ tuple& operator=(const tuple&) = default;
+
_GLIBCXX20_CONSTEXPR
void swap(tuple&) noexcept { /* no-op */ }
+
#if __cpp_lib_ranges_zip // >= C++23
- constexpr void swap(const tuple&) const noexcept { /* no-op */ }
+ template<same_as<tuple> _Tuple = tuple>
+ constexpr const tuple&
+ operator=(const _Tuple&) const noexcept
+ { return *this; }
+
+ constexpr void swap(const tuple&) const noexcept
+ { /* no-op */ }
#endif
- // We need the default since we're going to define no-op
- // allocator constructors.
- tuple() = default;
+
// No-op allocator constructors.
template<typename _Alloc>
_GLIBCXX20_CONSTEXPR
@@ -1999,6 +2012,48 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Alloc>
_GLIBCXX20_CONSTEXPR
tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept { }
+
+#if __cpp_lib_tuple_like // >= C++23
+ template<__tuple_like _UTuple>
+ requires (!is_same_v<remove_cvref_t<_UTuple>, tuple>)
+ && (!is_same_v<remove_cvref_t<_UTuple>, allocator_arg_t>)
+ && (tuple_size_v<remove_cvref_t<_UTuple>> == 0)
+ constexpr
+ tuple(_UTuple&&) noexcept { }
+
+ template<typename _Alloc, __tuple_like _UTuple>
+ requires (!is_same_v<remove_cvref_t<_UTuple>, tuple>)
+ && (tuple_size_v<remove_cvref_t<_UTuple>> == 0)
+ constexpr
+ tuple(allocator_arg_t, const _Alloc&, _UTuple&&) noexcept { }
+
+ template<__tuple_like _UTuple>
+ requires (!is_same_v<remove_cvref_t<_UTuple>, tuple>)
+ && (tuple_size_v<remove_cvref_t<_UTuple>> == 0)
+ constexpr tuple&
+ operator=(_UTuple&&) noexcept
+ { return *this; }
+
+ template<__tuple_like _UTuple>
+ requires (!is_same_v<remove_cvref_t<_UTuple>, tuple>)
+ && (tuple_size_v<remove_cvref_t<_UTuple>> == 0)
+ constexpr const tuple&
+ operator=(_UTuple&&) const noexcept
+ { return *this; }
+
+ template<__tuple_like _UTuple>
+ requires (!__is_tuple_v<_UTuple>) && (tuple_size_v<_UTuple> == 0)
+ [[nodiscard]]
+ friend constexpr bool
+ operator==(const tuple&, const _UTuple&) noexcept
+ { return true; }
+
+ template<__tuple_like _UTuple>
+ requires (!__is_tuple_v<_UTuple>) && (tuple_size_v<_UTuple> == 0)
+ friend constexpr strong_ordering
+ operator<=>(const tuple&, const _UTuple&) noexcept
+ { return strong_ordering::equal; }
+#endif // C++23
};
#if !(__cpp_concepts && __cpp_consteval && __cpp_conditional_explicit) // !C++20
@@ -2681,54 +2736,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); }
/// @cond undocumented
- template<size_t, typename, typename, size_t>
- struct __make_tuple_impl;
-
- template<size_t _Idx, typename _Tuple, typename... _Tp, size_t _Nm>
- struct __make_tuple_impl<_Idx, tuple<_Tp...>, _Tuple, _Nm>
- : __make_tuple_impl<_Idx + 1,
- tuple<_Tp..., __tuple_element_t<_Idx, _Tuple>>,
- _Tuple, _Nm>
- { };
+ template<typename _Tuple, typename _Idx_tuple>
+ struct __do_make_tuple;
- template<size_t _Nm, typename _Tuple, typename... _Tp>
- struct __make_tuple_impl<_Nm, tuple<_Tp...>, _Tuple, _Nm>
+ template<typename _Tuple, size_t... _Idx>
+ struct __do_make_tuple<_Tuple, _Index_tuple<_Idx...>>
{
- typedef tuple<_Tp...> __type;
+ using __type = tuple<__tuple_element_t<_Idx, _Tuple>...>;
};
- template<typename _Tuple>
- struct __do_make_tuple
- : __make_tuple_impl<0, tuple<>, _Tuple, tuple_size<_Tuple>::value>
- { };
-
// Returns the std::tuple equivalent of a tuple-like type.
- template<typename _Tuple>
+ template<typename _Tuple,
+ typename _Tup = __remove_cvref_t<_Tuple>,
+ typename _Indices = _Build_index_tuple<tuple_size<_Tup>::value>>
struct __make_tuple
- : public __do_make_tuple<__remove_cvref_t<_Tuple>>
+ : __do_make_tuple<_Tup, typename _Indices::__type>
{ };
- // Combines several std::tuple's into a single one.
+ // Combines several std::tuple types into a single one.
template<typename...>
struct __combine_tuples;
template<>
struct __combine_tuples<>
{
- typedef tuple<> __type;
+ using __type = tuple<>;
};
template<typename... _Ts>
struct __combine_tuples<tuple<_Ts...>>
{
- typedef tuple<_Ts...> __type;
+ using __type = tuple<_Ts...>;
+ };
+
+ template<typename... _T1s, typename... _T2s>
+ struct __combine_tuples<tuple<_T1s...>, tuple<_T2s...>>
+ {
+ using __type = tuple<_T1s..., _T2s...>;
};
- template<typename... _T1s, typename... _T2s, typename... _Rem>
- struct __combine_tuples<tuple<_T1s...>, tuple<_T2s...>, _Rem...>
+ template<typename... _T1s, typename... _T2s, typename... _T3s,
+ typename... _Rem>
+ struct __combine_tuples<tuple<_T1s...>, tuple<_T2s...>, tuple<_T3s...>,
+ _Rem...>
{
- typedef typename __combine_tuples<tuple<_T1s..., _T2s...>,
- _Rem...>::__type __type;
+ using _First = tuple<_T1s..., _T2s..., _T3s...>;
+ using _Second = typename __combine_tuples<_Rem...>::__type;
+ using __type = typename __combine_tuples<_First, _Second>::__type;
};
// Computes the result type of tuple_cat given a set of tuple-like types.
@@ -2835,6 +2889,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __x.swap(__y); }
#if __cpp_lib_ranges_zip // >= C++23
+ /// Exchange the values of two const tuples (if const elements can be swapped)
template<typename... _Elements>
requires (is_swappable_v<const _Elements> && ...)
constexpr void
@@ -2844,7 +2899,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif // C++23
#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
- /// Exchange the values of two const tuples (if const elements can be swapped)
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2766. Swapping non-swappable types
template<typename... _Elements>
_GLIBCXX20_CONSTEXPR
typename enable_if<!__and_<__is_swappable<_Elements>...>::value>::type
@@ -2939,19 +2995,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
#ifdef __cpp_lib_make_from_tuple // C++ >= 17
+ template <typename _Tp, typename _Tuple, typename _Seq
+ = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>>
+ constexpr bool __can_make_from_tuple = false;
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3528. make_from_tuple can perform (the equivalent of) a C-style cast
+ template <typename _Tp, typename _Tuple, size_t... _Idx>
+ constexpr bool __can_make_from_tuple<_Tp, _Tuple, index_sequence<_Idx...>>
+ = is_constructible_v<_Tp,
+ decltype(std::get<_Idx>(std::declval<_Tuple>()))...>;
+
template <typename _Tp, typename _Tuple, size_t... _Idx>
constexpr _Tp
__make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>)
- { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); }
+ {
+ static_assert(__can_make_from_tuple<_Tp, _Tuple, index_sequence<_Idx...>>);
+ return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...);
+ }
#if __cpp_lib_tuple_like // >= C++23
template <typename _Tp, __tuple_like _Tuple>
#else
template <typename _Tp, typename _Tuple>
#endif
- constexpr _Tp
+ constexpr auto
make_from_tuple(_Tuple&& __t)
noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>)
+#ifdef __cpp_concepts // >= C++20
+ -> _Tp
+ requires __can_make_from_tuple<_Tp, _Tuple>
+#else
+ -> __enable_if_t<__can_make_from_tuple<_Tp, _Tuple>, _Tp>
+#endif
{
constexpr size_t __n = tuple_size_v<remove_reference_t<_Tuple>>;
#if __has_builtin(__reference_constructs_from_temporary)
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 676cdf2..3f0bcc4e 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -41,11 +41,14 @@
#define __glibcxx_want_bool_constant
#define __glibcxx_want_bounded_array_traits
+#define __glibcxx_want_common_reference
+#define __glibcxx_want_constant_wrapper
#define __glibcxx_want_has_unique_object_representations
#define __glibcxx_want_integral_constant_callable
#define __glibcxx_want_is_aggregate
#define __glibcxx_want_is_constant_evaluated
#define __glibcxx_want_is_final
+#define __glibcxx_want_is_implicit_lifetime
#define __glibcxx_want_is_invocable
#define __glibcxx_want_is_layout_compatible
#define __glibcxx_want_is_nothrow_convertible
@@ -280,11 +283,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Forward declarations
template<typename>
- struct is_reference;
- template<typename>
- struct is_function;
- template<typename>
- struct is_void;
+ struct is_object;
template<typename>
struct remove_cv;
template<typename>
@@ -294,21 +293,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename>
struct __is_array_unknown_bounds;
+ // An object type which is not an unbounded array.
+ // It might still be an incomplete type, but if this is false_type
+ // then we can be certain it's not a complete object type.
+ template<typename _Tp>
+ using __maybe_complete_object_type
+ = __and_<is_object<_Tp>, __not_<__is_array_unknown_bounds<_Tp>>>;
+
// Helper functions that return false_type for incomplete classes,
// incomplete unions and arrays of known bound from those.
- template <typename _Tp, size_t = sizeof(_Tp)>
- constexpr true_type __is_complete_or_unbounded(__type_identity<_Tp>)
- { return {}; }
-
- template <typename _TypeIdentity,
- typename _NestedType = typename _TypeIdentity::type>
- constexpr typename __or_<
- is_reference<_NestedType>,
- is_function<_NestedType>,
- is_void<_NestedType>,
- __is_array_unknown_bounds<_NestedType>
- >::type __is_complete_or_unbounded(_TypeIdentity)
+ // More specialized overload for complete object types (returning true_type).
+ template<typename _Tp,
+ typename = __enable_if_t<__maybe_complete_object_type<_Tp>::value>,
+ size_t = sizeof(_Tp)>
+ constexpr true_type
+ __is_complete_or_unbounded(__type_identity<_Tp>)
+ { return {}; };
+
+ // Less specialized overload for reference and unknown-bound array types
+ // (returning true_type), and incomplete types (returning false_type).
+ template<typename _TypeIdentity,
+ typename _NestedType = typename _TypeIdentity::type>
+ constexpr typename __not_<__maybe_complete_object_type<_NestedType>>::type
+ __is_complete_or_unbounded(_TypeIdentity)
{ return {}; }
// __remove_cv_t (std::remove_cv_t for C++11).
@@ -459,6 +467,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_3>
: public true_type { };
#endif
+
+#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
+ __extension__
+ template<>
+ struct __is_integral_helper<__int128>
+ : public true_type { };
+
+ __extension__
+ template<>
+ struct __is_integral_helper<unsigned __int128>
+ : public true_type { };
+#endif
+
/// @endcond
/// is_integral
@@ -514,7 +535,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public true_type { };
#endif
-#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128)
+#ifdef _GLIBCXX_USE_FLOAT128
template<>
struct __is_floating_point_helper<__float128>
: public true_type { };
@@ -805,7 +826,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Check if a type is one of the signed integer types.
__extension__
template<typename _Tp>
- using __is_signed_integer = __is_one_of<__remove_cv_t<_Tp>,
+ using __is_signed_integer = __is_one_of<_Tp,
signed char, signed short, signed int, signed long,
signed long long
#if defined(__GLIBCXX_TYPE_INT_N_0)
@@ -820,12 +841,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if defined(__GLIBCXX_TYPE_INT_N_3)
, signed __GLIBCXX_TYPE_INT_N_3
#endif
+#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
+ , signed __int128
+#endif
>;
// Check if a type is one of the unsigned integer types.
__extension__
template<typename _Tp>
- using __is_unsigned_integer = __is_one_of<__remove_cv_t<_Tp>,
+ using __is_unsigned_integer = __is_one_of<_Tp,
unsigned char, unsigned short, unsigned int, unsigned long,
unsigned long long
#if defined(__GLIBCXX_TYPE_INT_N_0)
@@ -840,11 +864,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if defined(__GLIBCXX_TYPE_INT_N_3)
, unsigned __GLIBCXX_TYPE_INT_N_3
#endif
+#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
+ , unsigned __int128
+#endif
>;
// Check if a type is one of the signed or unsigned integer types.
+ // i.e. an integral type except bool, char, wchar_t, and charN_t.
template<typename _Tp>
- using __is_standard_integer
+ using __is_signed_or_unsigned_integer
= __or_<__is_signed_integer<_Tp>, __is_unsigned_integer<_Tp>>;
// __void_t (std::void_t for C++11)
@@ -1036,9 +1064,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __is_array_unknown_bounds<_Tp[]>
: public true_type
{ };
+ /// @endcond
// Destructible and constructible type properties.
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible)
+ /// is_destructible
+ template<typename _Tp>
+ struct is_destructible
+ : public __bool_constant<__is_destructible(_Tp)>
+ { };
+#else
+ /// @cond undocumented
+
// In N3290 is_destructible does not say anything about function
// types and abstract types, see LWG 2049. This implementation
// describes function types as non-destructible and all complete
@@ -1090,7 +1128,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
"template argument must be a complete class or an unbounded array");
};
+#endif
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible)
+ /// is_nothrow_destructible
+ template<typename _Tp>
+ struct is_nothrow_destructible
+ : public __bool_constant<__is_nothrow_destructible(_Tp)>
+ { };
+#else
/// @cond undocumented
// is_nothrow_destructible requires that is_destructible is
@@ -1144,6 +1190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
"template argument must be a complete class or an unbounded array");
};
+#endif
/// @cond undocumented
template<typename _Tp, typename... _Args>
@@ -1451,6 +1498,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"template argument must be a complete class or an unbounded array");
};
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible)
+ /// is_trivially_destructible
+ template<typename _Tp>
+ struct is_trivially_destructible
+ : public __bool_constant<__is_trivially_destructible(_Tp)>
+ { };
+#else
/// is_trivially_destructible
template<typename _Tp>
struct is_trivially_destructible
@@ -1460,7 +1514,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
"template argument must be a complete class or an unbounded array");
};
-
+#endif
/// has_virtual_destructor
template<typename _Tp>
@@ -1896,6 +1950,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __make_unsigned<__GLIBCXX_TYPE_INT_N_3>
{ using __type = unsigned __GLIBCXX_TYPE_INT_N_3; };
#endif
+#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
+ __extension__
+ template<>
+ struct __make_unsigned<__int128>
+ { using __type = unsigned __int128; };
+#endif
// Select between integral and enum: not possible to be both.
template<typename _Tp,
@@ -1942,8 +2002,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: __make_unsigned_selector_base
{
// With -fshort-enums, an enum may be as small as a char.
+ __extension__
using _UInts = _List<unsigned char, unsigned short, unsigned int,
- unsigned long, unsigned long long>;
+ unsigned long, unsigned long long
+#ifdef __SIZEOF_INT128__
+ , unsigned __int128
+#endif
+ >;
using __unsigned_type = typename __select<sizeof(_Tp), _UInts>::__type;
@@ -2056,6 +2121,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __make_signed<unsigned __GLIBCXX_TYPE_INT_N_3>
{ using __type = __GLIBCXX_TYPE_INT_N_3; };
#endif
+#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
+ __extension__
+ template<>
+ struct __make_signed<unsigned __int128>
+ { using __type = __int128; };
+#endif
// Select between integral and enum: not possible to be both.
template<typename _Tp,
@@ -3212,7 +3283,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Fn, typename... _ArgTypes>
struct __is_invocable
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
+ : __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
+#else
: __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type
+#endif
{ };
template<typename _Fn, typename _Tp, typename... _Args>
@@ -3263,8 +3338,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// __is_nothrow_invocable (std::is_nothrow_invocable for C++11)
template<typename _Fn, typename... _Args>
struct __is_nothrow_invocable
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable)
+ : __bool_constant<__is_nothrow_invocable(_Fn, _Args...)>
+#else
: __and_<__is_invocable<_Fn, _Args...>,
__call_is_nothrow_<_Fn, _Args...>>::type
+#endif
{ };
#pragma GCC diagnostic push
@@ -3573,8 +3652,13 @@ template <typename _Tp>
inline constexpr bool is_move_assignable_v
= __is_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>);
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible)
+template <typename _Tp>
+ inline constexpr bool is_destructible_v = __is_destructible(_Tp);
+#else
template <typename _Tp>
inline constexpr bool is_destructible_v = is_destructible<_Tp>::value;
+#endif
template <typename _Tp, typename... _Args>
inline constexpr bool is_trivially_constructible_v
@@ -3601,7 +3685,11 @@ template <typename _Tp>
= __is_trivially_assignable(__add_lval_ref_t<_Tp>,
__add_rval_ref_t<_Tp>);
-#if __cpp_concepts
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible)
+template <typename _Tp>
+ inline constexpr bool is_trivially_destructible_v
+ = __is_trivially_destructible(_Tp);
+#elif __cpp_concepts
template <typename _Tp>
inline constexpr bool is_trivially_destructible_v = false;
@@ -3646,9 +3734,15 @@ template <typename _Tp>
inline constexpr bool is_nothrow_move_assignable_v
= __is_nothrow_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>);
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible)
+template <typename _Tp>
+ inline constexpr bool is_nothrow_destructible_v
+ = __is_nothrow_destructible(_Tp);
+#else
template <typename _Tp>
inline constexpr bool is_nothrow_destructible_v =
is_nothrow_destructible<_Tp>::value;
+#endif
template <typename _Tp>
inline constexpr bool has_virtual_destructor_v
@@ -3704,10 +3798,19 @@ template <typename _From, typename _To>
inline constexpr bool is_convertible_v = is_convertible<_From, _To>::value;
#endif
template<typename _Fn, typename... _Args>
- inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value;
+ inline constexpr bool is_invocable_v
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
+ = __is_invocable(_Fn, _Args...);
+#else
+ = is_invocable<_Fn, _Args...>::value;
+#endif
template<typename _Fn, typename... _Args>
inline constexpr bool is_nothrow_invocable_v
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable)
+ = __is_nothrow_invocable(_Fn, _Args...);
+#else
= is_nothrow_invocable<_Fn, _Args...>::value;
+#endif
template<typename _Ret, typename _Fn, typename... _Args>
inline constexpr bool is_invocable_r_v
= is_invocable_r<_Ret, _Fn, _Args...>::value;
@@ -3959,6 +4062,22 @@ template<typename _Ret, typename _Fn, typename... _Args>
# endif
#endif
+#ifdef __cpp_lib_is_implicit_lifetime // C++ >= 23
+ /// True if the type is an implicit-lifetime type.
+ /// @since C++23
+
+ template<typename _Tp>
+ struct is_implicit_lifetime
+ : bool_constant<__builtin_is_implicit_lifetime(_Tp)>
+ { };
+
+ /// @ingroup variable_templates
+ /// @since C++23
+ template<typename _Tp>
+ inline constexpr bool is_implicit_lifetime_v
+ = __builtin_is_implicit_lifetime(_Tp);
+#endif
+
#ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
/// True if _Tp is a reference type, a _Up value can be bound to _Tp in
/// direct-initialization, and a temporary object would be bound to
@@ -4002,7 +4121,8 @@ template<typename _Ret, typename _Fn, typename... _Args>
#ifdef __cpp_lib_is_constant_evaluated // C++ >= 20 && HAVE_IS_CONST_EVAL
/// Returns true only when called during constant evaluation.
/// @since C++20
- constexpr inline bool
+ [[__gnu__::__always_inline__]]
+ constexpr bool
is_constant_evaluated() noexcept
{
#if __cpp_if_consteval >= 202106L
@@ -4113,7 +4233,7 @@ template<typename _Ret, typename _Fn, typename... _Args>
{ using type = _Tp0; };
/// @cond undocumented
- template<typename _Tp1, typename _Tp2, int _Bullet = 1, typename = void>
+ template<typename _Tp1, typename _Tp2, int _Bullet = 1>
struct __common_reference_impl
: __common_reference_impl<_Tp1, _Tp2, _Bullet + 1>
{ };
@@ -4126,46 +4246,38 @@ template<typename _Ret, typename _Fn, typename... _Args>
// If T1 and T2 are reference types and COMMON-REF(T1, T2) is well-formed, ...
template<typename _Tp1, typename _Tp2>
- struct __common_reference_impl<_Tp1&, _Tp2&, 1,
- void_t<__common_ref<_Tp1&, _Tp2&>>>
- { using type = __common_ref<_Tp1&, _Tp2&>; };
-
- template<typename _Tp1, typename _Tp2>
- struct __common_reference_impl<_Tp1&&, _Tp2&&, 1,
- void_t<__common_ref<_Tp1&&, _Tp2&&>>>
- { using type = __common_ref<_Tp1&&, _Tp2&&>; };
-
- template<typename _Tp1, typename _Tp2>
- struct __common_reference_impl<_Tp1&, _Tp2&&, 1,
- void_t<__common_ref<_Tp1&, _Tp2&&>>>
- { using type = __common_ref<_Tp1&, _Tp2&&>; };
-
- template<typename _Tp1, typename _Tp2>
- struct __common_reference_impl<_Tp1&&, _Tp2&, 1,
- void_t<__common_ref<_Tp1&&, _Tp2&>>>
- { using type = __common_ref<_Tp1&&, _Tp2&>; };
+ requires is_reference_v<_Tp1> && is_reference_v<_Tp2>
+ && requires { typename __common_ref<_Tp1, _Tp2>; }
+#if __cpp_lib_common_reference // C++ >= 20
+ && is_convertible_v<add_pointer_t<_Tp1>,
+ add_pointer_t<__common_ref<_Tp1, _Tp2>>>
+ && is_convertible_v<add_pointer_t<_Tp2>,
+ add_pointer_t<__common_ref<_Tp1, _Tp2>>>
+#endif
+ struct __common_reference_impl<_Tp1, _Tp2, 1>
+ { using type = __common_ref<_Tp1, _Tp2>; };
// Otherwise, if basic_common_reference<...>::type is well-formed, ...
template<typename _Tp1, typename _Tp2>
- struct __common_reference_impl<_Tp1, _Tp2, 2,
- void_t<__basic_common_ref<_Tp1, _Tp2>>>
+ requires requires { typename __basic_common_ref<_Tp1, _Tp2>; }
+ struct __common_reference_impl<_Tp1, _Tp2, 2>
{ using type = __basic_common_ref<_Tp1, _Tp2>; };
// Otherwise, if COND-RES(T1, T2) is well-formed, ...
template<typename _Tp1, typename _Tp2>
- struct __common_reference_impl<_Tp1, _Tp2, 3,
- void_t<__cond_res<_Tp1, _Tp2>>>
+ requires requires { typename __cond_res<_Tp1, _Tp2>; }
+ struct __common_reference_impl<_Tp1, _Tp2, 3>
{ using type = __cond_res<_Tp1, _Tp2>; };
// Otherwise, if common_type_t<T1, T2> is well-formed, ...
template<typename _Tp1, typename _Tp2>
- struct __common_reference_impl<_Tp1, _Tp2, 4,
- void_t<common_type_t<_Tp1, _Tp2>>>
+ requires requires { typename common_type_t<_Tp1, _Tp2>; }
+ struct __common_reference_impl<_Tp1, _Tp2, 4>
{ using type = common_type_t<_Tp1, _Tp2>; };
// Otherwise, there shall be no member type.
template<typename _Tp1, typename _Tp2>
- struct __common_reference_impl<_Tp1, _Tp2, 5, void>
+ struct __common_reference_impl<_Tp1, _Tp2, 5>
{ };
// Otherwise, if sizeof...(T) is greater than two, ...
@@ -4184,7 +4296,399 @@ template<typename _Ret, typename _Fn, typename... _Args>
{ };
/// @endcond
-#endif // C++2a
+#endif // C++20
+
+#if __cplusplus >= 201103L
+ // Stores a tuple of indices. Used by tuple and pair, and by bind() to
+ // extract the elements in a tuple.
+ template<size_t... _Indexes> struct _Index_tuple { };
+
+ // Builds an _Index_tuple<0, 1, 2, ..., _Num-1>.
+ template<size_t _Num>
+ struct _Build_index_tuple
+ {
+#if __has_builtin(__make_integer_seq)
+ template<typename, size_t... _Indices>
+ using _IdxTuple = _Index_tuple<_Indices...>;
+
+ // Clang defines __make_integer_seq for this purpose.
+ using __type = __make_integer_seq<_IdxTuple, size_t, _Num>;
+#else
+ // For GCC and other compilers, use __integer_pack instead.
+ using __type = _Index_tuple<__integer_pack(_Num)...>;
+#endif
+ };
+#endif // C++11
+
+#ifdef __cpp_lib_constant_wrapper // C++ >= 26
+ template<typename _Tp>
+ struct _CwFixedValue
+ {
+ using __type = _Tp;
+
+ constexpr
+ _CwFixedValue(__type __v) noexcept
+ : _M_data(__v) { }
+
+ __type _M_data;
+ };
+
+ template<typename _Tp, size_t _Extent>
+ struct _CwFixedValue<_Tp[_Extent]>
+ {
+ using __type = _Tp[_Extent];
+
+ constexpr
+ _CwFixedValue(_Tp (&__arr)[_Extent]) noexcept
+ : _CwFixedValue(__arr, typename _Build_index_tuple<_Extent>::__type())
+ { }
+
+ template<size_t... _Indices>
+ constexpr
+ _CwFixedValue(_Tp (&__arr)[_Extent], _Index_tuple<_Indices...>) noexcept
+ : _M_data{__arr[_Indices]...}
+ { }
+
+ _Tp _M_data[_Extent];
+ };
+
+ template<typename _Tp, size_t _Extent>
+ _CwFixedValue(_Tp (&)[_Extent]) -> _CwFixedValue<_Tp[_Extent]>;
+
+ template<_CwFixedValue _Xv,
+ typename = typename decltype(_CwFixedValue(_Xv))::__type>
+ struct constant_wrapper;
+
+ template<typename _Tp>
+ concept _ConstExprParam = requires
+ {
+ typename constant_wrapper<_Tp::value>;
+ };
+
+ struct _CwOperators
+ {
+ template<_ConstExprParam _Tp>
+ friend constexpr auto
+ operator+(_Tp) noexcept -> constant_wrapper<(+_Tp::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Tp>
+ friend constexpr auto
+ operator-(_Tp) noexcept -> constant_wrapper<(-_Tp::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Tp>
+ friend constexpr auto
+ operator~(_Tp) noexcept -> constant_wrapper<(~_Tp::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Tp>
+ friend constexpr auto
+ operator!(_Tp) noexcept -> constant_wrapper<(!_Tp::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Tp>
+ friend constexpr auto
+ operator&(_Tp) noexcept -> constant_wrapper<(&_Tp::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Tp>
+ friend constexpr auto
+ operator*(_Tp) noexcept -> constant_wrapper<(*_Tp::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator+(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value + _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator-(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value - _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator*(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value * _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator/(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value / _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator%(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value % _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator<<(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value << _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator>>(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value >> _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator&(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value & _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator|(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value | _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator^(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value ^ _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ requires (!is_constructible_v<bool, decltype(_Left::value)>
+ || !is_constructible_v<bool, decltype(_Right::value)>)
+ friend constexpr auto
+ operator&&(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value && _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ requires (!is_constructible_v<bool, decltype(_Left::value)>
+ || !is_constructible_v<bool, decltype(_Right::value)>)
+ friend constexpr auto
+ operator||(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value || _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator<=>(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value <=> _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator<(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value < _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator<=(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value <= _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator==(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value == _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator!=(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value != _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator>(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value > _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator>=(_Left, _Right) noexcept
+ -> constant_wrapper<(_Left::value >= _Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator,(_Left, _Right) noexcept = delete;
+
+ template<_ConstExprParam _Left, _ConstExprParam _Right>
+ friend constexpr auto
+ operator->*(_Left, _Right) noexcept
+ -> constant_wrapper<_Left::value->*(_Right::value)>
+ { return {}; }
+
+ template<_ConstExprParam _Tp, _ConstExprParam... _Args>
+ constexpr auto
+ operator()(this _Tp, _Args...) noexcept
+ requires
+ requires(_Args...) { constant_wrapper<_Tp::value(_Args::value...)>(); }
+ { return constant_wrapper<_Tp::value(_Args::value...)>{}; }
+
+ template<_ConstExprParam _Tp, _ConstExprParam... _Args>
+ constexpr auto
+ operator[](this _Tp, _Args...) noexcept
+ -> constant_wrapper<(_Tp::value[_Args::value...])>
+ { return {}; }
+
+ template<_ConstExprParam _Tp>
+ constexpr auto
+ operator++(this _Tp) noexcept
+ requires requires(_Tp::value_type __x) { ++__x; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return ++__x; }()>{};
+ }
+
+ template<_ConstExprParam _Tp>
+ constexpr auto
+ operator++(this _Tp, int) noexcept
+ requires requires(_Tp::value_type __x) { __x++; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x++; }()>{};
+ }
+
+ template<_ConstExprParam _Tp>
+ constexpr auto
+ operator--(this _Tp) noexcept
+ requires requires(_Tp::value_type __x) { --__x; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return --__x; }()>{};
+ }
+
+ template<_ConstExprParam _Tp>
+ constexpr auto
+ operator--(this _Tp, int) noexcept
+ requires requires(_Tp::value_type __x) { __x--; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x--; }()>{};
+ }
+
+ template<_ConstExprParam _Tp, _ConstExprParam _Right>
+ constexpr auto
+ operator+=(this _Tp, _Right) noexcept
+ requires requires(_Tp::value_type __x) { __x += _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x += _Right::value; }()>{};
+ }
+
+ template<_ConstExprParam _Tp, _ConstExprParam _Right>
+ constexpr auto
+ operator-=(this _Tp, _Right) noexcept
+ requires requires(_Tp::value_type __x) { __x -= _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x -= _Right::value; }()>{};
+ }
+
+ template<_ConstExprParam _Tp, _ConstExprParam _Right>
+ constexpr auto
+ operator*=(this _Tp, _Right) noexcept
+ requires requires(_Tp::value_type __x) { __x *= _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x *= _Right::value; }()>{};
+ }
+
+ template<_ConstExprParam _Tp, _ConstExprParam _Right>
+ constexpr auto
+ operator/=(this _Tp, _Right) noexcept
+ requires requires(_Tp::value_type __x) { __x /= _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x /= _Right::value; }()>{};
+ }
+
+ template<_ConstExprParam _Tp, _ConstExprParam _Right>
+ constexpr auto
+ operator%=(this _Tp, _Right) noexcept
+ requires requires(_Tp::value_type __x) { __x %= _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x %= _Right::value; }()>{};
+ }
+
+ template<_ConstExprParam _Tp, _ConstExprParam _Right>
+ constexpr auto
+ operator&=(this _Tp, _Right) noexcept
+ requires requires(_Tp::value_type __x) { __x &= _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x &= _Right::value; }()>{};
+ }
+
+ template<_ConstExprParam _Tp, _ConstExprParam _Right>
+ constexpr auto
+ operator|=(this _Tp, _Right) noexcept
+ requires requires(_Tp::value_type __x) { __x |= _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x |= _Right::value; }()>{};
+ }
+
+ template<_ConstExprParam _Tp, _ConstExprParam _Right>
+ constexpr auto
+ operator^=(this _Tp, _Right) noexcept
+ requires requires(_Tp::value_type __x) { __x ^= _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x ^= _Right::value; }()>{};
+ }
+
+ template<_ConstExprParam _Tp, _ConstExprParam _Right>
+ constexpr auto
+ operator<<=(this _Tp, _Right) noexcept
+ requires requires(_Tp::value_type __x) { __x <<= _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x <<= _Right::value; }()>{};
+ }
+
+ template<_ConstExprParam _Tp, _ConstExprParam _Right>
+ constexpr auto
+ operator>>=(this _Tp, _Right) noexcept
+ requires requires(_Tp::value_type __x) { __x >>= _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = _Tp::value; return __x >>= _Right::value; }()>{};
+ }
+ };
+
+ template<_CwFixedValue _Xv, typename>
+ struct constant_wrapper : _CwOperators
+ {
+ static constexpr const auto& value = _Xv._M_data;
+ using type = constant_wrapper;
+ using value_type = typename decltype(_Xv)::__type;
+
+ template<_ConstExprParam _Right>
+ constexpr auto
+ operator=(_Right) const noexcept
+ requires requires(value_type __x) { __x = _Right::value; }
+ {
+ return constant_wrapper<
+ [] { auto __x = value; return __x = _Right::value; }()>{};
+ }
+
+ constexpr
+ operator decltype(value)() const noexcept
+ { return value; }
+ };
+
+ template<_CwFixedValue _Tp>
+ constexpr auto cw = constant_wrapper<_Tp>{};
+#endif
/// @} group metaprogramming
diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility
index 1c15c75..0f6dd82 100644
--- a/libstdc++-v3/include/std/utility
+++ b/libstdc++-v3/include/std/utility
@@ -78,7 +78,7 @@
#include <bits/utility.h>
#if __cplusplus >= 202002L
-#include <ext/numeric_traits.h> // __is_standard_integer, __int_traits
+#include <bits/intcmp.h>
#endif
#if __cplusplus > 202302L
@@ -98,6 +98,7 @@
#define __glibcxx_want_tuple_element_t
#define __glibcxx_want_tuples_by_type
#define __glibcxx_want_unreachable
+#define __glibcxx_want_observable_checkpoint
#define __glibcxx_want_tuple_like
#define __glibcxx_want_constrained_equality
#include <bits/version.h>
@@ -128,80 +129,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void as_const(const _Tp&&) = delete;
#endif
-#ifdef __cpp_lib_integer_comparison_functions // C++ >= 20
- template<typename _Tp, typename _Up>
- constexpr bool
- cmp_equal(_Tp __t, _Up __u) noexcept
- {
- static_assert(__is_standard_integer<_Tp>::value);
- static_assert(__is_standard_integer<_Up>::value);
-
- if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
- return __t == __u;
- else if constexpr (is_signed_v<_Tp>)
- return __t >= 0 && make_unsigned_t<_Tp>(__t) == __u;
- else
- return __u >= 0 && __t == make_unsigned_t<_Up>(__u);
- }
-
- template<typename _Tp, typename _Up>
- constexpr bool
- cmp_not_equal(_Tp __t, _Up __u) noexcept
- { return !std::cmp_equal(__t, __u); }
-
- template<typename _Tp, typename _Up>
- constexpr bool
- cmp_less(_Tp __t, _Up __u) noexcept
- {
- static_assert(__is_standard_integer<_Tp>::value);
- static_assert(__is_standard_integer<_Up>::value);
-
- if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
- return __t < __u;
- else if constexpr (is_signed_v<_Tp>)
- return __t < 0 || make_unsigned_t<_Tp>(__t) < __u;
- else
- return __u >= 0 && __t < make_unsigned_t<_Up>(__u);
- }
-
- template<typename _Tp, typename _Up>
- constexpr bool
- cmp_greater(_Tp __t, _Up __u) noexcept
- { return std::cmp_less(__u, __t); }
-
- template<typename _Tp, typename _Up>
- constexpr bool
- cmp_less_equal(_Tp __t, _Up __u) noexcept
- { return !std::cmp_less(__u, __t); }
-
- template<typename _Tp, typename _Up>
- constexpr bool
- cmp_greater_equal(_Tp __t, _Up __u) noexcept
- { return !std::cmp_less(__t, __u); }
-
- template<typename _Res, typename _Tp>
- constexpr bool
- in_range(_Tp __t) noexcept
- {
- static_assert(__is_standard_integer<_Res>::value);
- static_assert(__is_standard_integer<_Tp>::value);
- using __gnu_cxx::__int_traits;
-
- if constexpr (is_signed_v<_Tp> == is_signed_v<_Res>)
- return __int_traits<_Res>::__min <= __t
- && __t <= __int_traits<_Res>::__max;
- else if constexpr (is_signed_v<_Tp>)
- return __t >= 0
- && make_unsigned_t<_Tp>(__t) <= __int_traits<_Res>::__max;
- else
- return __t <= make_unsigned_t<_Res>(__int_traits<_Res>::__max);
- }
-#endif // __cpp_lib_integer_comparison_functions
-
#ifdef __cpp_lib_to_underlying // C++ >= 23
/// Convert an object of enumeration type to its underlying type.
template<typename _Tp>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr underlying_type_t<_Tp>
to_underlying(_Tp __value) noexcept
{ return static_cast<underlying_type_t<_Tp>>(__value); }
@@ -234,6 +165,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
#endif
+
+#ifdef __cpp_lib_observable_checkpoint // C++ >= 26
+ /// Informs the compiler that prior actions are considered observable.
+ /**
+ * This may be used to limit the extent to which optimisations based on the
+ * assumed unreachability of undefined behaviour can propagate to earlier
+ * code.
+ *
+ * @since C++26
+ */
+ [[__gnu__::__always_inline__]]
+ inline void
+ observable_checkpoint() noexcept
+ {
+ return __builtin_observable_checkpoint();
+ }
+#endif
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
diff --git a/libstdc++-v3/include/std/valarray b/libstdc++-v3/include/std/valarray
index 82b58ef..ac15e79 100644
--- a/libstdc++-v3/include/std/valarray
+++ b/libstdc++-v3/include/std/valarray
@@ -720,7 +720,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
valarray<_Tp>::~valarray() _GLIBCXX_NOEXCEPT
{
std::__valarray_destroy_elements(_M_data, _M_data + _M_size);
- std::__valarray_release_memory(_M_data);
+ std::__valarray_release_memory(_M_data, _M_size);
}
template<typename _Tp>
@@ -736,7 +736,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (_M_data)
{
std::__valarray_destroy_elements(_M_data, _M_data + _M_size);
- std::__valarray_release_memory(_M_data);
+ std::__valarray_release_memory(_M_data, _M_size);
}
_M_size = __v._M_size;
_M_data = __valarray_get_storage<_Tp>(_M_size);
@@ -754,7 +754,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (_M_data)
{
std::__valarray_destroy_elements(_M_data, _M_data + _M_size);
- std::__valarray_release_memory(_M_data);
+ std::__valarray_release_memory(_M_data, _M_size);
}
_M_size = __v._M_size;
_M_data = __v._M_data;
@@ -776,7 +776,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (_M_data)
{
std::__valarray_destroy_elements(_M_data, _M_data + _M_size);
- std::__valarray_release_memory(_M_data);
+ std::__valarray_release_memory(_M_data, _M_size);
}
_M_size = __l.size();
_M_data = __valarray_get_storage<_Tp>(_M_size);
@@ -854,7 +854,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (_M_data)
{
std::__valarray_destroy_elements(_M_data, _M_data + _M_size);
- std::__valarray_release_memory(_M_data);
+ std::__valarray_release_memory(_M_data, _M_size);
}
_M_size = __e.size();
_M_data = __valarray_get_storage<_Tp>(_M_size);
@@ -1049,7 +1049,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
std::__valarray_destroy_elements(_M_data, _M_data + _M_size);
if (_M_size != __n)
{
- std::__valarray_release_memory(_M_data);
+ std::__valarray_release_memory(_M_data, _M_size);
_M_size = __n;
_M_data = __valarray_get_storage<_Tp>(__n);
}
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index ec46ff1..f2f5583 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -393,8 +393,29 @@ namespace __variant
_Variadic_union(in_place_index_t<_Np>, _Args&&...) = delete;
};
- template<bool __trivially_destructible, typename _First, typename... _Rest>
- union _Variadic_union<__trivially_destructible, _First, _Rest...>
+ template<typename _First, typename... _Rest>
+ union _Variadic_union<true, _First, _Rest...>
+ {
+ constexpr _Variadic_union() : _M_rest() { }
+
+ template<typename... _Args>
+ constexpr
+ _Variadic_union(in_place_index_t<0>, _Args&&... __args)
+ : _M_first(in_place_index<0>, std::forward<_Args>(__args)...)
+ { }
+
+ template<size_t _Np, typename... _Args>
+ constexpr
+ _Variadic_union(in_place_index_t<_Np>, _Args&&... __args)
+ : _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...)
+ { }
+
+ _Uninitialized<_First> _M_first;
+ _Variadic_union<true, _Rest...> _M_rest;
+ };
+
+ template<typename _First, typename... _Rest>
+ union _Variadic_union<false, _First, _Rest...>
{
constexpr _Variadic_union() : _M_rest() { }
@@ -410,24 +431,19 @@ namespace __variant
: _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...)
{ }
-#if __cpp_lib_variant >= 202106L
_Variadic_union(const _Variadic_union&) = default;
_Variadic_union(_Variadic_union&&) = default;
_Variadic_union& operator=(const _Variadic_union&) = default;
_Variadic_union& operator=(_Variadic_union&&) = default;
- ~_Variadic_union() = default;
-
// If any alternative type is not trivially destructible then we need a
// user-provided destructor that does nothing. The active alternative
// will be destroyed by _Variant_storage::_M_reset() instead of here.
- constexpr ~_Variadic_union()
- requires (!__trivially_destructible)
+ _GLIBCXX20_CONSTEXPR ~_Variadic_union()
{ }
-#endif
_Uninitialized<_First> _M_first;
- _Variadic_union<__trivially_destructible, _Rest...> _M_rest;
+ _Variadic_union<(is_trivially_destructible_v<_Rest> && ...), _Rest...> _M_rest;
};
// _Never_valueless_alt is true for variant alternatives that can
@@ -1387,6 +1403,8 @@ namespace __detail::__variant
noexcept(noexcept(__lhs.swap(__rhs)))
{ __lhs.swap(__rhs); }
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2766. Swapping non-swappable types
template<typename... _Types>
enable_if_t<!((is_move_constructible_v<_Types> && ...)
&& (is_swappable_v<_Types> && ...))>
diff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector
index a98ffb1..375011f 100644
--- a/libstdc++-v3/include/std/vector
+++ b/libstdc++-v3/include/std/vector
@@ -67,7 +67,6 @@
#include <bits/stl_uninitialized.h>
#include <bits/stl_vector.h>
#include <bits/stl_bvector.h>
-#include <bits/refwrap.h>
#include <bits/range_access.h>
#ifndef _GLIBCXX_EXPORT_TEMPLATE
@@ -113,20 +112,16 @@ namespace std _GLIBCXX_VISIBILITY(default)
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Alloc, typename _Predicate>
- _GLIBCXX20_CONSTEXPR
- inline typename vector<_Tp, _Alloc>::size_type
- erase_if(vector<_Tp, _Alloc>& __cont, _Predicate __pred)
+ constexpr typename _GLIBCXX_STD_C::vector<_Tp, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::vector<_Tp, _Alloc>& __cont, _Predicate __pred)
{
- using namespace __gnu_cxx;
- _GLIBCXX_STD_C::vector<_Tp, _Alloc>& __ucont = __cont;
const auto __osz = __cont.size();
- const auto __end = __ucont.end();
- auto __removed = std::__remove_if(__ucont.begin(), __end,
- __ops::__pred_iter(std::ref(__pred)));
+ const auto __end = __cont.end();
+ auto __removed = std::__remove_if(__cont.begin(), __end,
+ std::move(__pred));
if (__removed != __end)
{
- __cont.erase(__niter_wrap(__cont.begin(), __removed),
- __cont.end());
+ __cont.erase(__removed, __end);
return __osz - __cont.size();
}
@@ -135,25 +130,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Alloc,
typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
- _GLIBCXX20_CONSTEXPR
- inline typename vector<_Tp, _Alloc>::size_type
- erase(vector<_Tp, _Alloc>& __cont, const _Up& __value)
- {
- using namespace __gnu_cxx;
- _GLIBCXX_STD_C::vector<_Tp, _Alloc>& __ucont = __cont;
- const auto __osz = __cont.size();
- const auto __end = __ucont.end();
- auto __removed = std::__remove_if(__ucont.begin(), __end,
- __ops::__iter_equals_val(__value));
- if (__removed != __end)
- {
- __cont.erase(__niter_wrap(__cont.begin(), __removed),
- __cont.end());
- return __osz - __cont.size();
- }
+ constexpr typename _GLIBCXX_STD_C::vector<_Tp, _Alloc>::size_type
+ erase(_GLIBCXX_STD_C::vector<_Tp, _Alloc>& __cont, const _Up& __value)
+ { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); }
- return 0;
- }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // __cpp_lib_erase_if
@@ -186,6 +166,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
private:
__format::__formatter_int<_CharT> _M_f;
};
+
+#if __glibcxx_print >= 202406L
+ template<>
+ inline constexpr bool
+ enable_nonlocking_formatter_optimization<_GLIBCXX_STD_C::_Bit_reference> = true;
+#endif
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // __glibcxx_format_ranges