aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/include')
-rw-r--r--libstdc++-v3/include/Makefile.am6
-rw-r--r--libstdc++-v3/include/Makefile.in6
-rw-r--r--libstdc++-v3/include/bits/allocated_ptr.h96
-rw-r--r--libstdc++-v3/include/bits/atomic_timed_wait.h441
-rw-r--r--libstdc++-v3/include/bits/atomic_wait.h487
-rw-r--r--libstdc++-v3/include/bits/basic_string.h4
-rw-r--r--libstdc++-v3/include/bits/boost_concept_check.h1
-rw-r--r--libstdc++-v3/include/bits/c++config6
-rw-r--r--libstdc++-v3/include/bits/chrono.h2
-rw-r--r--libstdc++-v3/include/bits/chrono_io.h2947
-rw-r--r--libstdc++-v3/include/bits/cpyfunc_impl.h273
-rw-r--r--libstdc++-v3/include/bits/formatfwd.h29
-rw-r--r--libstdc++-v3/include/bits/funcref_impl.h202
-rw-r--r--libstdc++-v3/include/bits/funcwrap.h621
-rw-r--r--libstdc++-v3/include/bits/indirect.h833
-rw-r--r--libstdc++-v3/include/bits/iterator_concepts.h13
-rw-r--r--libstdc++-v3/include/bits/max_size_type.h15
-rw-r--r--libstdc++-v3/include/bits/mofunc_impl.h82
-rw-r--r--libstdc++-v3/include/bits/move_only_function.h218
-rw-r--r--libstdc++-v3/include/bits/ptr_traits.h2
-rw-r--r--libstdc++-v3/include/bits/ranges_algo.h1376
-rw-r--r--libstdc++-v3/include/bits/ranges_base.h40
-rw-r--r--libstdc++-v3/include/bits/semaphore_base.h350
-rw-r--r--libstdc++-v3/include/bits/std_abs.h9
-rw-r--r--libstdc++-v3/include/bits/stl_algo.h110
-rw-r--r--libstdc++-v3/include/bits/stl_construct.h72
-rw-r--r--libstdc++-v3/include/bits/stl_deque.h2
-rw-r--r--libstdc++-v3/include/bits/stl_iterator.h12
-rw-r--r--libstdc++-v3/include/bits/stl_tempbuf.h2
-rw-r--r--libstdc++-v3/include/bits/stl_uninitialized.h48
-rw-r--r--libstdc++-v3/include/bits/stl_vector.h13
-rw-r--r--libstdc++-v3/include/bits/utility.h17
-rw-r--r--libstdc++-v3/include/bits/vector.tcc6
-rw-r--r--libstdc++-v3/include/bits/version.def93
-rw-r--r--libstdc++-v3/include/bits/version.h103
-rw-r--r--libstdc++-v3/include/c_global/ccomplex2
-rw-r--r--libstdc++-v3/include/c_global/ciso64618
-rw-r--r--libstdc++-v3/include/c_global/cstdalign2
-rw-r--r--libstdc++-v3/include/c_global/cstdbool2
-rw-r--r--libstdc++-v3/include/c_global/ctgmath2
-rw-r--r--libstdc++-v3/include/debug/debug.h2
-rw-r--r--libstdc++-v3/include/ext/atomicity.h4
-rw-r--r--libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp3
-rw-r--r--libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp2
-rw-r--r--libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp31
-rw-r--r--libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp4
-rw-r--r--libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/node.hpp8
-rw-r--r--libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/node.hpp8
-rw-r--r--libstdc++-v3/include/precompiled/stdc++.h1
-rw-r--r--libstdc++-v3/include/pstl/glue_numeric_impl.h16
-rw-r--r--libstdc++-v3/include/pstl/numeric_impl.h36
-rw-r--r--libstdc++-v3/include/std/algorithm1
-rw-r--r--libstdc++-v3/include/std/barrier199
-rw-r--r--libstdc++-v3/include/std/bit4
-rw-r--r--libstdc++-v3/include/std/chrono24
-rw-r--r--libstdc++-v3/include/std/complex26
-rw-r--r--libstdc++-v3/include/std/expected4
-rw-r--r--libstdc++-v3/include/std/flat_map16
-rw-r--r--libstdc++-v3/include/std/format584
-rw-r--r--libstdc++-v3/include/std/functional32
-rw-r--r--libstdc++-v3/include/std/latch26
-rw-r--r--libstdc++-v3/include/std/mdspan1041
-rw-r--r--libstdc++-v3/include/std/memory6
-rw-r--r--libstdc++-v3/include/std/mutex2
-rw-r--r--libstdc++-v3/include/std/numeric6
-rw-r--r--libstdc++-v3/include/std/optional47
-rw-r--r--libstdc++-v3/include/std/ranges12
-rw-r--r--libstdc++-v3/include/std/semaphore31
-rw-r--r--libstdc++-v3/include/std/sstream202
-rw-r--r--libstdc++-v3/include/std/stop_token7
-rw-r--r--libstdc++-v3/include/std/tuple24
-rw-r--r--libstdc++-v3/include/std/type_traits106
-rw-r--r--libstdc++-v3/include/std/utility2
73 files changed, 8218 insertions, 2862 deletions
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 537774c..cc402f0 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -38,6 +38,7 @@ std_freestanding = \
${std_srcdir}/generator \
${std_srcdir}/iterator \
${std_srcdir}/limits \
+ ${std_srcdir}/mdspan \
${std_srcdir}/memory \
${std_srcdir}/numbers \
${std_srcdir}/numeric \
@@ -193,6 +194,7 @@ bits_headers = \
${bits_srcdir}/chrono_io.h \
${bits_srcdir}/codecvt.h \
${bits_srcdir}/cow_string.h \
+ ${bits_srcdir}/cpyfunc_impl.h \
${bits_srcdir}/deque.tcc \
${bits_srcdir}/erase_if.h \
${bits_srcdir}/formatfwd.h \
@@ -203,10 +205,13 @@ bits_headers = \
${bits_srcdir}/fs_ops.h \
${bits_srcdir}/fs_path.h \
${bits_srcdir}/fstream.tcc \
+ ${bits_srcdir}/funcref_impl.h \
+ ${bits_srcdir}/funcwrap.h \
${bits_srcdir}/gslice.h \
${bits_srcdir}/gslice_array.h \
${bits_srcdir}/hashtable.h \
${bits_srcdir}/hashtable_policy.h \
+ ${bits_srcdir}/indirect.h \
${bits_srcdir}/indirect_array.h \
${bits_srcdir}/ios_base.h \
${bits_srcdir}/istream.tcc \
@@ -222,7 +227,6 @@ bits_headers = \
${bits_srcdir}/mask_array.h \
${bits_srcdir}/memory_resource.h \
${bits_srcdir}/mofunc_impl.h \
- ${bits_srcdir}/move_only_function.h \
${bits_srcdir}/new_allocator.h \
${bits_srcdir}/node_handle.h \
${bits_srcdir}/ostream.tcc \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 7b96b22..0ef8564 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -396,6 +396,7 @@ std_freestanding = \
${std_srcdir}/generator \
${std_srcdir}/iterator \
${std_srcdir}/limits \
+ ${std_srcdir}/mdspan \
${std_srcdir}/memory \
${std_srcdir}/numbers \
${std_srcdir}/numeric \
@@ -546,6 +547,7 @@ bits_freestanding = \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/chrono_io.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/codecvt.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/cow_string.h \
+@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/cpyfunc_impl.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/deque.tcc \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/erase_if.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/formatfwd.h \
@@ -556,10 +558,13 @@ bits_freestanding = \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/fs_ops.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/fs_path.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/fstream.tcc \
+@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/funcref_impl.h \
+@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/funcwrap.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/gslice.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/gslice_array.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/hashtable.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/hashtable_policy.h \
+@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/indirect.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/indirect_array.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/ios_base.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/istream.tcc \
@@ -575,7 +580,6 @@ bits_freestanding = \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/mask_array.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/memory_resource.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/mofunc_impl.h \
-@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/move_only_function.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/new_allocator.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/node_handle.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/ostream.tcc \
diff --git a/libstdc++-v3/include/bits/allocated_ptr.h b/libstdc++-v3/include/bits/allocated_ptr.h
index 0b2b6fe..aa5355f 100644
--- a/libstdc++-v3/include/bits/allocated_ptr.h
+++ b/libstdc++-v3/include/bits/allocated_ptr.h
@@ -36,6 +36,7 @@
# include <type_traits>
# include <bits/ptr_traits.h>
# include <bits/alloc_traits.h>
+# include <bits/utility.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -136,6 +137,101 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return { std::__allocate_guarded(__a) };
}
+ // An RAII type that acquires memory from an allocator.
+ // N.B. 'scoped' here in in the RAII sense, not the scoped allocator model,
+ // so this has nothing to do with `std::scoped_allocator_adaptor`.
+ // This class can be used to simplify the common pattern:
+ //
+ // auto ptr = alloc.allocate(1);
+ // try {
+ // std::construct_at(std::to_address(ptr), args);
+ // m_ptr = ptr;
+ // } catch (...) {
+ // alloc.deallocate(ptr, 1);
+ // throw;
+ // }
+ //
+ // Instead you can do:
+ //
+ // _Scoped_allocation sa(alloc);
+ // m_ptr = std::construct_at(sa.get(), args);
+ // (void) sa.release();
+ //
+ // Or even simpler:
+ //
+ // _Scoped_allocation sa(alloc, std::in_place, args);
+ // m_ptr = sa.release();
+ //
+ template<typename _Alloc>
+ struct _Scoped_allocation
+ {
+ using value_type = typename allocator_traits<_Alloc>::value_type;
+ using pointer = typename allocator_traits<_Alloc>::pointer;
+
+ // Use `a` to allocate memory for `n` objects.
+ constexpr explicit
+ _Scoped_allocation(const _Alloc& __a, size_t __n = 1)
+ : _M_a(__a), _M_n(__n), _M_p(_M_a.allocate(__n))
+ { }
+
+#if __glibcxx_optional >= 201606L
+ // Allocate memory for a single object and if that succeeds,
+ // construct an object using args.
+ //
+ // Does not do uses-allocator construction; don't use if you need that.
+ //
+ // CAUTION: the destructor will *not* destroy this object, it will only
+ // free the memory. That means the following pattern is unsafe:
+ //
+ // _Scoped_allocation sa(alloc, in_place, args);
+ // potentially_throwing_operations();
+ // return sa.release();
+ //
+ // If the middle operation throws, the object will not be destroyed.
+ template<typename... _Args>
+ constexpr explicit
+ _Scoped_allocation(const _Alloc& __a, in_place_t, _Args&&... __args)
+ : _Scoped_allocation(__a, 1)
+ {
+ // The target constructor has completed, so if the next line throws,
+ // the destructor will deallocate the memory.
+ allocator_traits<_Alloc>::construct(_M_a, get(),
+ std::forward<_Args>(__args)...);
+ }
+#endif
+
+ _GLIBCXX20_CONSTEXPR
+ ~_Scoped_allocation()
+ {
+ if (_M_p) [[__unlikely__]]
+ _M_a.deallocate(_M_p, _M_n);
+ }
+
+ _Scoped_allocation(_Scoped_allocation&&) = delete;
+
+ constexpr _Alloc
+ get_allocator() const noexcept { return _M_a; }
+
+ constexpr value_type*
+ get() const noexcept
+ { return std::__to_address(_M_p); }
+
+ [[__nodiscard__]]
+ constexpr pointer
+ release() noexcept { return std::__exchange(_M_p, nullptr); }
+
+ private:
+ [[__no_unique_address__]] _Alloc _M_a;
+ size_t _M_n;
+ pointer _M_p;
+ };
+
+#if __glibcxx_optional >= 201606L && __cpp_deduction_guides >= 201606L
+ template<typename _Alloc, typename... _Args>
+ _Scoped_allocation(_Alloc, in_place_t, _Args...)
+ -> _Scoped_allocation<_Alloc>;
+#endif
+
/// @endcond
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
index 9a6ac95..30f7ff6 100644
--- a/libstdc++-v3/include/bits/atomic_timed_wait.h
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -37,7 +37,6 @@
#include <bits/atomic_wait.h>
#if __glibcxx_atomic_wait
-#include <bits/functional_hash.h>
#include <bits/this_thread_sleep.h>
#include <bits/chrono.h>
@@ -70,383 +69,165 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Dur>& __atime) noexcept
{
using __w_dur = typename __wait_clock_t::duration;
- return chrono::ceil<__w_dur>(__atime);
+ if constexpr (is_same_v<__w_dur, _Dur>)
+ return __atime;
+ else
+ return chrono::ceil<__w_dur>(__atime);
}
#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
#define _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT
- // returns true if wait ended before timeout
- template<typename _Dur>
- bool
- __platform_wait_until_impl(const __platform_wait_t* __addr,
- __platform_wait_t __old,
- const chrono::time_point<__wait_clock_t, _Dur>&
- __atime) noexcept
- {
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- struct timespec __rt =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
- auto __e = syscall (SYS_futex, __addr,
- static_cast<int>(__futex_wait_flags::
- __wait_bitset_private),
- __old, &__rt, nullptr,
- static_cast<int>(__futex_wait_flags::
- __bitset_match_any));
-
- if (__e)
- {
- if (errno == ETIMEDOUT)
- return false;
- if (errno != EINTR && errno != EAGAIN)
- __throw_system_error(errno);
- }
- return true;
- }
-
- // returns true if wait ended before timeout
- template<typename _Clock, typename _Dur>
- bool
- __platform_wait_until(const __platform_wait_t* __addr, __platform_wait_t __old,
- const chrono::time_point<_Clock, _Dur>& __atime)
- {
- if constexpr (is_same_v<__wait_clock_t, _Clock>)
- {
- return __platform_wait_until_impl(__addr, __old, __atime);
- }
- else
- {
- if (!__platform_wait_until_impl(__addr, __old,
- __to_wait_clock(__atime)))
- {
- // We got a timeout when measured against __clock_t but
- // we need to check against the caller-supplied clock
- // to tell whether we should return a timeout.
- if (_Clock::now() < __atime)
- return true;
- }
- return false;
- }
- }
#else
-// define _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT and implement __platform_wait_until()
+// define _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT and implement __platform_wait_until
// if there is a more efficient primitive supported by the platform
-// (e.g. __ulock_wait())which is better than pthread_cond_clockwait
-#endif // ! PLATFORM_TIMED_WAIT
+// (e.g. __ulock_wait) which is better than pthread_cond_clockwait.
+#endif // ! HAVE_LINUX_FUTEX
-#ifdef _GLIBCXX_HAS_GTHREADS
- // Returns true if wait ended before timeout.
- // _Clock must be either steady_clock or system_clock.
- template<typename _Clock, typename _Dur>
- bool
- __cond_wait_until_impl(__condvar& __cv, mutex& __mx,
- const chrono::time_point<_Clock, _Dur>& __atime)
- {
- static_assert(std::__is_one_of<_Clock, chrono::steady_clock,
- chrono::system_clock>::value);
-
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
+ __wait_result_type
+ __wait_until_impl(const void* __addr, __wait_args_base& __args,
+ const __wait_clock_t::duration& __atime);
- __gthread_time_t __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
-#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
- if constexpr (is_same_v<chrono::steady_clock, _Clock>)
- __cv.wait_until(__mx, CLOCK_MONOTONIC, __ts);
- else
-#endif
- __cv.wait_until(__mx, __ts);
- return _Clock::now() < __atime;
- }
-
- // returns true if wait ended before timeout
template<typename _Clock, typename _Dur>
- bool
- __cond_wait_until(__condvar& __cv, mutex& __mx,
- const chrono::time_point<_Clock, _Dur>& __atime)
+ __wait_result_type
+ __wait_until(const void* __addr, __wait_args_base& __args,
+ const chrono::time_point<_Clock, _Dur>& __atime) noexcept
{
-#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
- if constexpr (is_same_v<_Clock, chrono::steady_clock>)
- return __detail::__cond_wait_until_impl(__cv, __mx, __atime);
- else
-#endif
- if constexpr (is_same_v<_Clock, chrono::system_clock>)
- return __detail::__cond_wait_until_impl(__cv, __mx, __atime);
- else
- {
- if (__cond_wait_until_impl(__cv, __mx,
- __to_wait_clock(__atime)))
- {
- // We got a timeout when measured against __clock_t but
- // we need to check against the caller-supplied clock
- // to tell whether we should return a timeout.
- if (_Clock::now() < __atime)
- return true;
- }
- return false;
- }
- }
-#endif // _GLIBCXX_HAS_GTHREADS
+ auto __at = __detail::__to_wait_clock(__atime);
+ auto __res = __detail::__wait_until_impl(__addr, __args,
+ __at.time_since_epoch());
- struct __timed_waiter_pool : __waiter_pool_base
- {
- // returns true if wait ended before timeout
- template<typename _Clock, typename _Dur>
- bool
- _M_do_wait_until(__platform_wait_t* __addr, __platform_wait_t __old,
- const chrono::time_point<_Clock, _Dur>& __atime)
- {
-#ifdef _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT
- return __platform_wait_until(__addr, __old, __atime);
-#else
- __platform_wait_t __val;
- __atomic_load(__addr, &__val, __ATOMIC_RELAXED);
- if (__val == __old)
+ if constexpr (!is_same_v<__wait_clock_t, _Clock>)
+ if (__res._M_timeout)
{
- lock_guard<mutex> __l(_M_mtx);
- return __cond_wait_until(_M_cv, _M_mtx, __atime);
+ // We got a timeout when measured against __clock_t but
+ // we need to check against the caller-supplied clock
+ // to tell whether we should return a timeout.
+ if (_Clock::now() < __atime)
+ __res._M_timeout = false;
}
- else
- return true;
-#endif // _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT
- }
- };
-
- struct __timed_backoff_spin_policy
- {
- __wait_clock_t::time_point _M_deadline;
- __wait_clock_t::time_point _M_t0;
-
- template<typename _Clock, typename _Dur>
- __timed_backoff_spin_policy(chrono::time_point<_Clock, _Dur>
- __deadline = _Clock::time_point::max(),
- chrono::time_point<_Clock, _Dur>
- __t0 = _Clock::now()) noexcept
- : _M_deadline(__to_wait_clock(__deadline))
- , _M_t0(__to_wait_clock(__t0))
- { }
-
- bool
- operator()() const noexcept
- {
- using namespace literals::chrono_literals;
- auto __now = __wait_clock_t::now();
- if (_M_deadline <= __now)
- return false;
-
- // FIXME: this_thread::sleep_for not available #ifdef _GLIBCXX_NO_SLEEP
-
- auto __elapsed = __now - _M_t0;
- if (__elapsed > 128ms)
- {
- this_thread::sleep_for(64ms);
- }
- else if (__elapsed > 64us)
- {
- this_thread::sleep_for(__elapsed / 2);
- }
- else if (__elapsed > 4us)
- {
- __thread_yield();
- }
- else
- return false;
- return true;
+ return __res;
}
- };
- template<typename _EntersWait>
- struct __timed_waiter : __waiter_base<__timed_waiter_pool>
+ template<typename _Rep, typename _Period>
+ __wait_result_type
+ __wait_for(const void* __addr, __wait_args_base& __args,
+ const chrono::duration<_Rep, _Period>& __rtime) noexcept
{
- using __base_type = __waiter_base<__timed_waiter_pool>;
-
- template<typename _Tp>
- __timed_waiter(const _Tp* __addr) noexcept
- : __base_type(__addr)
- {
- if constexpr (_EntersWait::value)
- _M_w._M_enter_wait();
- }
-
- ~__timed_waiter()
- {
- if constexpr (_EntersWait::value)
- _M_w._M_leave_wait();
- }
-
- // returns true if wait ended before timeout
- template<typename _Tp, typename _ValFn,
- typename _Clock, typename _Dur>
- bool
- _M_do_wait_until_v(_Tp __old, _ValFn __vfn,
- const chrono::time_point<_Clock, _Dur>&
- __atime) noexcept
- {
- __platform_wait_t __val;
- if (_M_do_spin(__old, std::move(__vfn), __val,
- __timed_backoff_spin_policy(__atime)))
- return true;
- return __base_type::_M_w._M_do_wait_until(__base_type::_M_addr, __val, __atime);
- }
-
- // returns true if wait ended before timeout
- template<typename _Pred,
- typename _Clock, typename _Dur>
- bool
- _M_do_wait_until(_Pred __pred, __platform_wait_t __val,
- const chrono::time_point<_Clock, _Dur>&
- __atime) noexcept
- {
- for (auto __now = _Clock::now(); __now < __atime;
- __now = _Clock::now())
- {
- if (__base_type::_M_w._M_do_wait_until(
- __base_type::_M_addr, __val, __atime)
- && __pred())
- return true;
-
- if (__base_type::_M_do_spin(__pred, __val,
- __timed_backoff_spin_policy(__atime, __now)))
- return true;
- }
- return false;
- }
-
- // returns true if wait ended before timeout
- template<typename _Pred,
- typename _Clock, typename _Dur>
- bool
- _M_do_wait_until(_Pred __pred,
- const chrono::time_point<_Clock, _Dur>&
- __atime) noexcept
- {
- __platform_wait_t __val;
- if (__base_type::_M_do_spin(__pred, __val,
- __timed_backoff_spin_policy(__atime)))
- return true;
- return _M_do_wait_until(__pred, __val, __atime);
- }
-
- template<typename _Tp, typename _ValFn,
- typename _Rep, typename _Period>
- bool
- _M_do_wait_for_v(_Tp __old, _ValFn __vfn,
- const chrono::duration<_Rep, _Period>&
- __rtime) noexcept
- {
- __platform_wait_t __val;
- if (_M_do_spin_v(__old, std::move(__vfn), __val))
- return true;
-
- if (!__rtime.count())
- return false; // no rtime supplied, and spin did not acquire
-
- auto __reltime = chrono::ceil<__wait_clock_t::duration>(__rtime);
-
- return __base_type::_M_w._M_do_wait_until(
- __base_type::_M_addr,
- __val,
- chrono::steady_clock::now() + __reltime);
- }
-
- template<typename _Pred,
- typename _Rep, typename _Period>
- bool
- _M_do_wait_for(_Pred __pred,
- const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ if (!__rtime.count())
{
- __platform_wait_t __val;
- if (__base_type::_M_do_spin(__pred, __val))
- return true;
-
- if (!__rtime.count())
- return false; // no rtime supplied, and spin did not acquire
-
- auto __reltime = chrono::ceil<__wait_clock_t::duration>(__rtime);
-
- return _M_do_wait_until(__pred, __val,
- chrono::steady_clock::now() + __reltime);
+ // no rtime supplied, just spin a bit
+ __args._M_flags |= __wait_flags::__do_spin | __wait_flags::__spin_only;
+ return __detail::__wait_impl(__addr, __args);
}
- };
- using __enters_timed_wait = __timed_waiter<std::true_type>;
- using __bare_timed_wait = __timed_waiter<std::false_type>;
+ auto const __reltime = chrono::ceil<__wait_clock_t::duration>(__rtime);
+ auto const __atime = chrono::steady_clock::now() + __reltime;
+ return __detail::__wait_until(__addr, __args, __atime);
+ }
} // namespace __detail
// returns true if wait ended before timeout
- template<typename _Tp, typename _ValFn,
+ template<typename _Tp,
+ typename _Pred, typename _ValFn,
typename _Clock, typename _Dur>
bool
- __atomic_wait_address_until_v(const _Tp* __addr, _Tp&& __old, _ValFn&& __vfn,
- const chrono::time_point<_Clock, _Dur>&
- __atime) noexcept
+ __atomic_wait_address_until(const _Tp* __addr, _Pred&& __pred,
+ _ValFn&& __vfn,
+ const chrono::time_point<_Clock, _Dur>& __atime,
+ bool __bare_wait = false) noexcept
{
- __detail::__enters_timed_wait __w{__addr};
- return __w._M_do_wait_until_v(__old, __vfn, __atime);
+ __detail::__wait_args __args{ __addr, __bare_wait };
+ _Tp __val = __args._M_setup_wait(__addr, __vfn);
+ while (!__pred(__val))
+ {
+ auto __res = __detail::__wait_until(__addr, __args, __atime);
+ if (__res._M_timeout)
+ return false; // C++26 will also return last observed __val
+ __val = __args._M_setup_wait(__addr, __vfn, __res);
+ }
+ return true; // C++26 will also return last observed __val
}
- template<typename _Tp, typename _Pred,
- typename _Clock, typename _Dur>
+ template<typename _Clock, typename _Dur>
bool
- __atomic_wait_address_until(const _Tp* __addr, _Pred __pred,
- const chrono::time_point<_Clock, _Dur>&
- __atime) noexcept
+ __atomic_wait_address_until_v(const __detail::__platform_wait_t* __addr,
+ __detail::__platform_wait_t __old,
+ int __order,
+ const chrono::time_point<_Clock, _Dur>& __atime,
+ bool __bare_wait = false) noexcept
{
- __detail::__enters_timed_wait __w{__addr};
- return __w._M_do_wait_until(__pred, __atime);
+#ifndef _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT
+ __glibcxx_assert(false); // This function can't be used for proxy wait.
+#endif
+ __detail::__wait_args __args{ __addr, __old, __order, __bare_wait };
+ auto __res = __detail::__wait_until(__addr, __args, __atime);
+ return !__res._M_timeout; // C++26 will also return last observed __val
}
- template<typename _Pred,
+ template<typename _Tp, typename _ValFn,
typename _Clock, typename _Dur>
bool
- __atomic_wait_address_until_bare(const __detail::__platform_wait_t* __addr,
- _Pred __pred,
- const chrono::time_point<_Clock, _Dur>&
- __atime) noexcept
+ __atomic_wait_address_until_v(const _Tp* __addr, _Tp&& __old,
+ _ValFn&& __vfn,
+ const chrono::time_point<_Clock, _Dur>& __atime,
+ bool __bare_wait = false) noexcept
{
- __detail::__bare_timed_wait __w{__addr};
- return __w._M_do_wait_until(__pred, __atime);
+ auto __pfn = [&](const _Tp& __val) {
+ return !__detail::__atomic_eq(__old, __val);
+ };
+ return std::__atomic_wait_address_until(__addr, __pfn, __vfn, __atime,
+ __bare_wait);
}
- template<typename _Tp, typename _ValFn,
+ template<typename _Tp,
+ typename _Pred, typename _ValFn,
typename _Rep, typename _Period>
bool
- __atomic_wait_address_for_v(const _Tp* __addr, _Tp&& __old, _ValFn&& __vfn,
- const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ __atomic_wait_address_for(const _Tp* __addr, _Pred&& __pred,
+ _ValFn&& __vfn,
+ const chrono::duration<_Rep, _Period>& __rtime,
+ bool __bare_wait = false) noexcept
{
- __detail::__enters_timed_wait __w{__addr};
- return __w._M_do_wait_for_v(__old, __vfn, __rtime);
+ __detail::__wait_args __args{ __addr, __bare_wait };
+ _Tp __val = __args._M_setup_wait(__addr, __vfn);
+ while (!__pred(__val))
+ {
+ auto __res = __detail::__wait_for(__addr, __args, __rtime);
+ if (__res._M_timeout)
+ return false; // C++26 will also return last observed __val
+ __val = __args._M_setup_wait(__addr, __vfn);
+ }
+ return true; // C++26 will also return last observed __val
}
- template<typename _Tp, typename _Pred,
- typename _Rep, typename _Period>
+ template<typename _Rep, typename _Period>
bool
- __atomic_wait_address_for(const _Tp* __addr, _Pred __pred,
- const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ __atomic_wait_address_for_v(const __detail::__platform_wait_t* __addr,
+ __detail::__platform_wait_t __old,
+ int __order,
+ const chrono::duration<_Rep, _Period>& __rtime,
+ bool __bare_wait = false) noexcept
{
-
- __detail::__enters_timed_wait __w{__addr};
- return __w._M_do_wait_for(__pred, __rtime);
+#ifndef _GLIBCXX_HAVE_PLATFORM_TIMED_WAIT
+ __glibcxx_assert(false); // This function can't be used for proxy wait.
+#endif
+ __detail::__wait_args __args{ __addr, __old, __order, __bare_wait };
+ auto __res = __detail::__wait_for(__addr, __args, __rtime);
+ return !__res._M_timeout; // C++26 will also return last observed __val
}
- template<typename _Pred,
+ template<typename _Tp, typename _ValFn,
typename _Rep, typename _Period>
bool
- __atomic_wait_address_for_bare(const __detail::__platform_wait_t* __addr,
- _Pred __pred,
- const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ __atomic_wait_address_for_v(const _Tp* __addr, _Tp&& __old, _ValFn&& __vfn,
+ const chrono::duration<_Rep, _Period>& __rtime,
+ bool __bare_wait = false) noexcept
{
- __detail::__bare_timed_wait __w{__addr};
- return __w._M_do_wait_for(__pred, __rtime);
+ auto __pfn = [&](const _Tp& __val) {
+ return !__detail::__atomic_eq(__old, __val);
+ };
+ return __atomic_wait_address_for(__addr, __pfn, forward<_ValFn>(__vfn),
+ __rtime, __bare_wait);
}
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index 6d1554f..9515147 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -37,20 +37,10 @@
#include <bits/version.h>
#if __glibcxx_atomic_wait
-#include <cstdint>
-#include <bits/functional_hash.h>
#include <bits/gthr.h>
#include <ext/numeric_traits.h>
-#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
-# include <cerrno>
-# include <climits>
-# include <unistd.h>
-# include <syscall.h>
-# include <bits/functexcept.h>
-#endif
-
-# include <bits/std_mutex.h> // std::mutex, std::__condvar
+#include <bits/stl_pair.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -81,60 +71,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#ifdef _GLIBCXX_HAVE_PLATFORM_WAIT
= is_scalar_v<_Tp>
&& ((sizeof(_Tp) == sizeof(__detail::__platform_wait_t))
- && (alignof(_Tp*) >= __detail::__platform_wait_alignment));
+ && (alignof(_Tp) >= __detail::__platform_wait_alignment));
#else
= false;
#endif
namespace __detail
{
-#ifdef _GLIBCXX_HAVE_LINUX_FUTEX
- enum class __futex_wait_flags : int
- {
-#ifdef _GLIBCXX_HAVE_LINUX_FUTEX_PRIVATE
- __private_flag = 128,
-#else
- __private_flag = 0,
-#endif
- __wait = 0,
- __wake = 1,
- __wait_bitset = 9,
- __wake_bitset = 10,
- __wait_private = __wait | __private_flag,
- __wake_private = __wake | __private_flag,
- __wait_bitset_private = __wait_bitset | __private_flag,
- __wake_bitset_private = __wake_bitset | __private_flag,
- __bitset_match_any = -1
- };
-
- template<typename _Tp>
- void
- __platform_wait(const _Tp* __addr, __platform_wait_t __val) noexcept
- {
- auto __e = syscall (SYS_futex, static_cast<const void*>(__addr),
- static_cast<int>(__futex_wait_flags::__wait_private),
- __val, nullptr);
- if (!__e || errno == EAGAIN)
- return;
- if (errno != EINTR)
- __throw_system_error(errno);
- }
-
- template<typename _Tp>
- void
- __platform_notify(const _Tp* __addr, bool __all) noexcept
- {
- syscall (SYS_futex, static_cast<const void*>(__addr),
- static_cast<int>(__futex_wait_flags::__wake_private),
- __all ? INT_MAX : 1);
- }
-#endif
-
inline void
__thread_yield() noexcept
{
#if defined _GLIBCXX_HAS_GTHREADS && defined _GLIBCXX_USE_SCHED_YIELD
- __gthread_yield();
+ __gthread_yield();
#endif
}
@@ -148,334 +96,193 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
}
- inline constexpr auto __atomic_spin_count_relax = 12;
- inline constexpr auto __atomic_spin_count = 16;
-
- struct __default_spin_policy
- {
- bool
- operator()() const noexcept
- { return false; }
- };
-
- template<typename _Pred,
- typename _Spin = __default_spin_policy>
- bool
- __atomic_spin(_Pred& __pred, _Spin __spin = _Spin{ }) noexcept
- {
- for (auto __i = 0; __i < __atomic_spin_count; ++__i)
- {
- if (__pred())
- return true;
-
- if (__i < __atomic_spin_count_relax)
- __detail::__thread_relax();
- else
- __detail::__thread_yield();
- }
-
- while (__spin())
- {
- if (__pred())
- return true;
- }
-
- return false;
- }
-
// return true if equal
template<typename _Tp>
- bool __atomic_compare(const _Tp& __a, const _Tp& __b)
+ inline bool
+ __atomic_eq(const _Tp& __a, const _Tp& __b)
{
// TODO make this do the correct padding bit ignoring comparison
return __builtin_memcmp(&__a, &__b, sizeof(_Tp)) == 0;
}
- struct __waiter_pool_base
+ // lightweight std::optional<__platform_wait_t>
+ struct __wait_result_type
{
- // Don't use std::hardware_destructive_interference_size here because we
- // don't want the layout of library types to depend on compiler options.
- static constexpr auto _S_align = 64;
-
- alignas(_S_align) __platform_wait_t _M_wait = 0;
-
-#ifndef _GLIBCXX_HAVE_PLATFORM_WAIT
- mutex _M_mtx;
-#endif
+ __platform_wait_t _M_val;
+ unsigned char _M_has_val : 1; // _M_val value was loaded before return.
+ unsigned char _M_timeout : 1; // Waiting function ended with timeout.
+ unsigned char _M_unused : 6; // padding
+ };
- alignas(_S_align) __platform_wait_t _M_ver = 0;
+ enum class __wait_flags : __UINT_LEAST32_TYPE__
+ {
+ __abi_version = 0,
+ __proxy_wait = 1,
+ __track_contention = 2,
+ __do_spin = 4,
+ __spin_only = 8, // Ignored unless __do_spin is also set.
+ // __abi_version_mask = 0xffff0000,
+ };
-#ifndef _GLIBCXX_HAVE_PLATFORM_WAIT
- __condvar _M_cv;
-#endif
- __waiter_pool_base() = default;
+ [[__gnu__::__always_inline__]]
+ constexpr __wait_flags
+ operator|(__wait_flags __l, __wait_flags __r) noexcept
+ {
+ using _Ut = underlying_type_t<__wait_flags>;
+ return static_cast<__wait_flags>(static_cast<_Ut>(__l)
+ | static_cast<_Ut>(__r));
+ }
- void
- _M_enter_wait() noexcept
- { __atomic_fetch_add(&_M_wait, 1, __ATOMIC_SEQ_CST); }
+ [[__gnu__::__always_inline__]]
+ constexpr __wait_flags&
+ operator|=(__wait_flags& __l, __wait_flags __r) noexcept
+ { return __l = __l | __r; }
- void
- _M_leave_wait() noexcept
- { __atomic_fetch_sub(&_M_wait, 1, __ATOMIC_RELEASE); }
+ // Simple aggregate containing arguments used by implementation details.
+ struct __wait_args_base
+ {
+ __wait_flags _M_flags;
+ int _M_order = __ATOMIC_ACQUIRE;
+ __platform_wait_t _M_old = 0;
+ void* _M_wait_state = nullptr;
+ // Test whether _M_flags & __flags is non-zero.
bool
- _M_waiting() const noexcept
+ operator&(__wait_flags __flags) const noexcept
{
- __platform_wait_t __res;
- __atomic_load(&_M_wait, &__res, __ATOMIC_SEQ_CST);
- return __res != 0;
+ using _Ut = underlying_type_t<__wait_flags>;
+ return static_cast<_Ut>(_M_flags) & static_cast<_Ut>(__flags);
}
+ };
- void
- _M_notify(__platform_wait_t* __addr, [[maybe_unused]] bool __all,
- bool __bare) noexcept
- {
-#ifdef _GLIBCXX_HAVE_PLATFORM_WAIT
- if (__addr == &_M_ver)
- {
- __atomic_fetch_add(__addr, 1, __ATOMIC_SEQ_CST);
- __all = true;
- }
-
- if (__bare || _M_waiting())
- __platform_notify(__addr, __all);
-#else
+ // Utility for populating a __wait_args_base structure.
+ struct __wait_args : __wait_args_base
+ {
+ template<typename _Tp> requires (!is_same_v<_Tp, __wait_args>)
+ explicit
+ __wait_args(const _Tp* __addr, bool __bare_wait = false) noexcept
+ : __wait_args_base{ _S_flags_for(__addr, __bare_wait) }
+ { }
+
+ __wait_args(const __platform_wait_t* __addr, __platform_wait_t __old,
+ int __order, bool __bare_wait = false) noexcept
+ : __wait_args_base{ _S_flags_for(__addr, __bare_wait), __order, __old }
+ { }
+
+ __wait_args(const __wait_args&) noexcept = default;
+ __wait_args& operator=(const __wait_args&) noexcept = default;
+
+ template<typename _ValFn,
+ typename _Tp = decay_t<decltype(std::declval<_ValFn&>()())>>
+ _Tp
+ _M_setup_wait(const void* __addr, _ValFn __vfn,
+ __wait_result_type __res = {})
{
- lock_guard<mutex> __l(_M_mtx);
- __atomic_fetch_add(__addr, 1, __ATOMIC_RELAXED);
+ if constexpr (__platform_wait_uses_type<_Tp>)
+ {
+ // If the wait is not proxied, the value we check when waiting
+ // is the value of the atomic variable itself.
+
+ if (__res._M_has_val) // The previous wait loaded a recent value.
+ {
+ _M_old = __res._M_val;
+ return __builtin_bit_cast(_Tp, __res._M_val);
+ }
+ else // Load the value from __vfn
+ {
+ _Tp __val = __vfn();
+ _M_old = __builtin_bit_cast(__platform_wait_t, __val);
+ return __val;
+ }
+ }
+ else // It's a proxy wait and the proxy's _M_ver is used.
+ {
+ if (__res._M_has_val) // The previous wait loaded a recent value.
+ _M_old = __res._M_val;
+ else // Load _M_ver from the proxy (must happen before __vfn()).
+ _M_load_proxy_wait_val(__addr);
+ return __vfn();
+ }
}
- if (__bare || _M_waiting())
- _M_cv.notify_all();
-#endif
- }
-
- static __waiter_pool_base&
- _S_for(const void* __addr) noexcept
- {
- constexpr __UINTPTR_TYPE__ __ct = 16;
- static __waiter_pool_base __w[__ct];
- auto __key = ((__UINTPTR_TYPE__)__addr >> 2) % __ct;
- return __w[__key];
- }
- };
- struct __waiter_pool : __waiter_pool_base
- {
+ private:
+ // Populates _M_wait_state and _M_old from the proxy for __addr.
void
- _M_do_wait(const __platform_wait_t* __addr, __platform_wait_t __old) noexcept
- {
-#ifdef _GLIBCXX_HAVE_PLATFORM_WAIT
- __platform_wait(__addr, __old);
-#else
- __platform_wait_t __val;
- __atomic_load(__addr, &__val, __ATOMIC_SEQ_CST);
- if (__val == __old)
- {
- lock_guard<mutex> __l(_M_mtx);
- __atomic_load(__addr, &__val, __ATOMIC_RELAXED);
- if (__val == __old)
- _M_cv.wait(_M_mtx);
- }
-#endif // __GLIBCXX_HAVE_PLATFORM_WAIT
- }
- };
+ _M_load_proxy_wait_val(const void* __addr);
- template<typename _Tp>
- struct __waiter_base
- {
- using __waiter_type = _Tp;
-
- __waiter_type& _M_w;
- __platform_wait_t* _M_addr;
-
- template<typename _Up>
- static __platform_wait_t*
- _S_wait_addr(const _Up* __a, __platform_wait_t* __b)
- {
- if constexpr (__platform_wait_uses_type<_Up>)
- return reinterpret_cast<__platform_wait_t*>(const_cast<_Up*>(__a));
- else
- return __b;
- }
-
- static __waiter_type&
- _S_for(const void* __addr) noexcept
+ template<typename _Tp>
+ static constexpr __wait_flags
+ _S_flags_for(const _Tp*, bool __bare_wait) noexcept
{
- static_assert(sizeof(__waiter_type) == sizeof(__waiter_pool_base));
- auto& res = __waiter_pool_base::_S_for(__addr);
- return reinterpret_cast<__waiter_type&>(res);
+ using enum __wait_flags;
+ __wait_flags __res = __abi_version | __do_spin;
+ if (!__bare_wait)
+ __res |= __track_contention;
+ if constexpr (!__platform_wait_uses_type<_Tp>)
+ __res |= __proxy_wait;
+ return __res;
}
+ };
- template<typename _Up>
- explicit __waiter_base(const _Up* __addr) noexcept
- : _M_w(_S_for(__addr))
- , _M_addr(_S_wait_addr(__addr, &_M_w._M_ver))
- { }
-
- void
- _M_notify(bool __all, bool __bare = false) noexcept
- { _M_w._M_notify(_M_addr, __all, __bare); }
-
- template<typename _Up, typename _ValFn,
- typename _Spin = __default_spin_policy>
- static bool
- _S_do_spin_v(__platform_wait_t* __addr,
- const _Up& __old, _ValFn __vfn,
- __platform_wait_t& __val,
- _Spin __spin = _Spin{ })
- {
- auto const __pred = [=]
- { return !__detail::__atomic_compare(__old, __vfn()); };
-
- if constexpr (__platform_wait_uses_type<_Up>)
- {
- __builtin_memcpy(&__val, &__old, sizeof(__val));
- }
- else
- {
- __atomic_load(__addr, &__val, __ATOMIC_ACQUIRE);
- }
- return __atomic_spin(__pred, __spin);
- }
-
- template<typename _Up, typename _ValFn,
- typename _Spin = __default_spin_policy>
- bool
- _M_do_spin_v(const _Up& __old, _ValFn __vfn,
- __platform_wait_t& __val,
- _Spin __spin = _Spin{ })
- { return _S_do_spin_v(_M_addr, __old, __vfn, __val, __spin); }
-
- template<typename _Pred,
- typename _Spin = __default_spin_policy>
- static bool
- _S_do_spin(const __platform_wait_t* __addr,
- _Pred __pred,
- __platform_wait_t& __val,
- _Spin __spin = _Spin{ })
- {
- __atomic_load(__addr, &__val, __ATOMIC_ACQUIRE);
- return __atomic_spin(__pred, __spin);
- }
-
- template<typename _Pred,
- typename _Spin = __default_spin_policy>
- bool
- _M_do_spin(_Pred __pred, __platform_wait_t& __val,
- _Spin __spin = _Spin{ })
- { return _S_do_spin(_M_addr, __pred, __val, __spin); }
- };
-
- template<typename _EntersWait>
- struct __waiter : __waiter_base<__waiter_pool>
- {
- using __base_type = __waiter_base<__waiter_pool>;
+ __wait_result_type
+ __wait_impl(const void* __addr, __wait_args_base&);
- template<typename _Tp>
- explicit __waiter(const _Tp* __addr) noexcept
- : __base_type(__addr)
- {
- if constexpr (_EntersWait::value)
- _M_w._M_enter_wait();
- }
+ void
+ __notify_impl(const void* __addr, bool __all, const __wait_args_base&);
+ } // namespace __detail
- ~__waiter()
+ // Wait on __addr while __pred(__vfn()) is false.
+ // If __bare_wait is false, increment a counter while waiting.
+ // For callers that keep their own count of waiters, use __bare_wait=true.
+ template<typename _Tp, typename _Pred, typename _ValFn>
+ void
+ __atomic_wait_address(const _Tp* __addr, _Pred&& __pred, _ValFn&& __vfn,
+ bool __bare_wait = false) noexcept
+ {
+ __detail::__wait_args __args{ __addr, __bare_wait };
+ _Tp __val = __args._M_setup_wait(__addr, __vfn);
+ while (!__pred(__val))
{
- if constexpr (_EntersWait::value)
- _M_w._M_leave_wait();
+ auto __res = __detail::__wait_impl(__addr, __args);
+ __val = __args._M_setup_wait(__addr, __vfn, __res);
}
+ // C++26 will return __val
+ }
- template<typename _Tp, typename _ValFn>
- void
- _M_do_wait_v(_Tp __old, _ValFn __vfn)
- {
- do
- {
- __platform_wait_t __val;
- if (__base_type::_M_do_spin_v(__old, __vfn, __val))
- return;
- __base_type::_M_w._M_do_wait(__base_type::_M_addr, __val);
- }
- while (__detail::__atomic_compare(__old, __vfn()));
- }
-
- template<typename _Pred>
- void
- _M_do_wait(_Pred __pred) noexcept
- {
- do
- {
- __platform_wait_t __val;
- if (__base_type::_M_do_spin(__pred, __val))
- return;
- __base_type::_M_w._M_do_wait(__base_type::_M_addr, __val);
- }
- while (!__pred());
- }
- };
-
- using __enters_wait = __waiter<std::true_type>;
- using __bare_wait = __waiter<std::false_type>;
- } // namespace __detail
+ // Wait on __addr while *__addr == __old is true.
+ inline void
+ __atomic_wait_address_v(const __detail::__platform_wait_t* __addr,
+ __detail::__platform_wait_t __old,
+ int __order, bool __bare_wait = false)
+ {
+#ifndef _GLIBCXX_HAVE_PLATFORM_WAIT
+ __glibcxx_assert(false); // This function can't be used for proxy wait.
+#endif
+ __detail::__wait_args __args{ __addr, __old, __order, __bare_wait };
+ // C++26 will not ignore the return value here
+ __detail::__wait_impl(__addr, __args);
+ }
+ // Wait on __addr while __vfn() == __old is true.
template<typename _Tp, typename _ValFn>
void
__atomic_wait_address_v(const _Tp* __addr, _Tp __old,
_ValFn __vfn) noexcept
{
- __detail::__enters_wait __w(__addr);
- __w._M_do_wait_v(__old, __vfn);
- }
-
- template<typename _Tp, typename _Pred>
- void
- __atomic_wait_address(const _Tp* __addr, _Pred __pred) noexcept
- {
- __detail::__enters_wait __w(__addr);
- __w._M_do_wait(__pred);
- }
-
- // This call is to be used by atomic types which track contention externally
- template<typename _Pred>
- void
- __atomic_wait_address_bare(const __detail::__platform_wait_t* __addr,
- _Pred __pred) noexcept
- {
-#ifdef _GLIBCXX_HAVE_PLATFORM_WAIT
- do
- {
- __detail::__platform_wait_t __val;
- if (__detail::__bare_wait::_S_do_spin(__addr, __pred, __val))
- return;
- __detail::__platform_wait(__addr, __val);
- }
- while (!__pred());
-#else // !_GLIBCXX_HAVE_PLATFORM_WAIT
- __detail::__bare_wait __w(__addr);
- __w._M_do_wait(__pred);
-#endif
+ auto __pfn = [&](const _Tp& __val)
+ { return !__detail::__atomic_eq(__old, __val); };
+ std::__atomic_wait_address(__addr, __pfn, forward<_ValFn>(__vfn));
}
template<typename _Tp>
void
- __atomic_notify_address(const _Tp* __addr, bool __all) noexcept
+ __atomic_notify_address(const _Tp* __addr, bool __all,
+ bool __bare_wait = false) noexcept
{
- __detail::__bare_wait __w(__addr);
- __w._M_notify(__all);
+ __detail::__wait_args __args{ __addr, __bare_wait };
+ __detail::__notify_impl(__addr, __all, __args);
}
- // This call is to be used by atomic types which track contention externally
- inline void
- __atomic_notify_address_bare(const __detail::__platform_wait_t* __addr,
- bool __all) noexcept
- {
-#ifdef _GLIBCXX_HAVE_PLATFORM_WAIT
- __detail::__platform_notify(__addr, __all);
-#else
- __detail::__bare_wait __w(__addr);
- __w._M_notify(__all, true);
-#endif
- }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // __glibcxx_atomic_wait
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index a087e63..7081049 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -1164,7 +1164,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{
size_type __sz = _M_string_length;
if (__sz > max_size ())
- __builtin_unreachable ();
+ __builtin_unreachable();
return __sz;
}
@@ -1279,7 +1279,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
size_t __sz = _M_is_local() ? size_type(_S_local_capacity)
: _M_allocated_capacity;
if (__sz < _S_local_capacity || __sz > max_size ())
- __builtin_unreachable ();
+ __builtin_unreachable();
return __sz;
}
diff --git a/libstdc++-v3/include/bits/boost_concept_check.h b/libstdc++-v3/include/bits/boost_concept_check.h
index 7a99f74..a1f488d 100644
--- a/libstdc++-v3/include/bits/boost_concept_check.h
+++ b/libstdc++-v3/include/bits/boost_concept_check.h
@@ -68,6 +68,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
+#pragma GCC diagnostic ignored "-Wlong-long"
#define _IsUnused __attribute__ ((__unused__))
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index 676f5ee..eec3a4a 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -273,6 +273,12 @@
#define _GLIBCXX_NOEXCEPT_QUAL
#endif
+#if __cpp_auto_cast
+# define _GLIBCXX_AUTO_CAST(X) auto(X)
+#else
+# define _GLIBCXX_AUTO_CAST(X) ::std::__decay_t<decltype((X))>(X)
+#endif
+
// Macro for extern template, ie controlling template linkage via use
// of extern keyword on template declaration. As documented in the g++
// manual, it inhibits all implicit instantiations and is used
diff --git a/libstdc++-v3/include/bits/chrono.h b/libstdc++-v3/include/bits/chrono.h
index fad2162..8de8e75 100644
--- a/libstdc++-v3/include/bits/chrono.h
+++ b/libstdc++-v3/include/bits/chrono.h
@@ -1244,6 +1244,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
now() noexcept;
// Map to C API
+ [[__gnu__::__always_inline__]]
static std::time_t
to_time_t(const time_point& __t) noexcept
{
@@ -1251,6 +1252,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
(__t.time_since_epoch()).count());
}
+ [[__gnu__::__always_inline__]]
static time_point
from_time_t(std::time_t __t) noexcept
{
diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h
index b7f6f5f..bcf9830 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -189,11 +189,6 @@ namespace __format
{
[[noreturn,__gnu__::__always_inline__]]
inline void
- __no_timezone_available()
- { __throw_format_error("format error: no timezone available for %Z or %z"); }
-
- [[noreturn,__gnu__::__always_inline__]]
- inline void
__not_valid_for_duration()
{ __throw_format_error("format error: chrono-format-spec not valid for "
"chrono::duration"); }
@@ -204,45 +199,352 @@ namespace __format
{ __throw_format_error("format error: chrono-format-spec not valid for "
"argument type"); }
+ // Represents the information provided by a chrono type.
+ // e.g. month_weekday has month and weekday but no year or time of day,
+ // hh_mm_ss has time of day but no date, sys_time is time_point+timezone.
+ enum class _ChronoParts : unsigned short {
+ _None = 0, _TotalSeconds = 1u, _Subseconds = 1u << 2,
+
+ // time since epoch
+ _EpochUnits = 1u << 3, _UnitSuffix = 1u << 4,
+ _EpochSeconds = _EpochUnits | _TotalSeconds,
+
+ // local (wall) time
+ _LocalDays = 1u << 5,
+ _LocalSeconds = _LocalDays | _TotalSeconds,
+
+ _Year = 1u << 6, _Month = 1u << 7, _Day = 1u << 8,
+ _Weekday = 1u << 9, _WeekdayIndex = 1u << 10, _DayOfYear = 1u << 11,
+ _IndexedWeekday = _Weekday | _WeekdayIndex,
+ _YearMonthDay = _Year | _Month | _Day,
+ _Date = _LocalDays | _YearMonthDay | _IndexedWeekday | _DayOfYear,
+
+ _HoursMinutesSeconds = 1u << 12,
+ _TimeOfDay = _HoursMinutesSeconds | _Subseconds,
+ _Time = _TimeOfDay | _TotalSeconds,
+ _EpochTime = _Time | _EpochUnits | _UnitSuffix,
+ _DateTime = _Date | _Time,
+
+ _ZoneAbbrev = 1u << 13, _ZoneOffset = 1u << 14,
+ _TimeZone = _ZoneAbbrev | _ZoneOffset,
+ _ZonedDateTime = _DateTime | _TimeZone,
+ };
+
+ [[__gnu__::__always_inline__]]
+ constexpr _ChronoParts
+ operator&(_ChronoParts __x, _ChronoParts __y) noexcept
+ { return static_cast<_ChronoParts>((unsigned)__x & (unsigned)__y); }
+
+ [[__gnu__::__always_inline__]]
+ constexpr _ChronoParts&
+ operator&=(_ChronoParts& __x, _ChronoParts __y) noexcept
+ { return __x = __x & __y; }
+
+ [[__gnu__::__always_inline__]]
+ constexpr _ChronoParts
+ operator|(_ChronoParts __x, _ChronoParts __y) noexcept
+ { return static_cast<_ChronoParts>((unsigned short)__x | (unsigned short)__y); }
+
+ [[__gnu__::__always_inline__]]
+ constexpr _ChronoParts&
+ operator|=(_ChronoParts& __x, _ChronoParts __y) noexcept
+ { return __x = __x | __y; }
+
+ // returns copy of x with all bits from y unset.
+ [[__gnu__::__always_inline__]]
+ constexpr _ChronoParts
+ operator-(_ChronoParts __x, _ChronoParts __y) noexcept
+ { return static_cast<_ChronoParts>((unsigned short)__x & ~(unsigned short)__y); }
+
+ // unsets all bits of x that are set in y
+ [[__gnu__::__always_inline__]]
+ constexpr _ChronoParts&
+ operator-=(_ChronoParts& __x, _ChronoParts __y) noexcept
+ { return __x = __x - __y; }
+
+ [[__gnu__::__always_inline__]]
+ constexpr bool
+ operator==(_ChronoParts __x, decltype(nullptr)) noexcept
+ { return (unsigned short)__x == 0; }
+
template<typename _CharT>
struct _ChronoSpec : _Spec<_CharT>
{
- basic_string_view<_CharT> _M_chrono_specs;
+ // When _M_prec_kind is _WP_none, the _M_prec contains the default
+ // value of fraction digits to be used for time '%S'.
- // Use one of the reserved bits in __format::_Spec<C>.
+ // Placed in tail-padding of __format::_Spec<C>.
// This indicates that a locale-dependent conversion specifier such as
// %a is used in the chrono-specs. This is not the same as the
// _Spec<C>::_M_localized member which indicates that "L" was present
// in the format-spec, e.g. "{:L%a}" is localized and locale-specific,
// but "{:L}" is only localized and "{:%a}" is only locale-specific.
- constexpr bool
- _M_locale_specific() const noexcept
- { return this->_M_reserved; }
+ unsigned _M_locale_specific : 1;
+ // Indicates that we are handling duration.
+ unsigned _M_time_only : 1;
+ // Indicates that duration should be treated as floating point.
+ unsigned _M_floating_point_rep : 1;
+ // Indicate that duration uses user-defined representation.
+ unsigned _M_custom_rep : 1;
+ unsigned _M_unused : 4;
+
+ // Chrono parts required by format specs
+ _ChronoParts _M_needed;
+ basic_string_view<_CharT> _M_chrono_specs;
- constexpr void
- _M_locale_specific(bool __b) noexcept
- { this->_M_reserved = __b; }
+ [[__gnu__::__always_inline__]]
+ constexpr bool
+ _M_needs(_ChronoParts __parts) const
+ { return (_M_needed & __parts) != 0; }
};
- // Represents the information provided by a chrono type.
- // e.g. month_weekday has month and weekday but no year or time of day,
- // hh_mm_ss has time of day but no date, sys_time is time_point+timezone.
- enum _ChronoParts {
- _Year = 1, _Month = 2, _Day = 4, _Weekday = 8, _TimeOfDay = 16,
- _TimeZone = 32,
- _Date = _Year | _Month | _Day | _Weekday,
- _DateTime = _Date | _TimeOfDay,
- _ZonedDateTime = _DateTime | _TimeZone,
- _Duration = 128 // special case
+ template<typename _CharT>
+ struct _ChronoFormats
+ {
+ using _String_view = basic_string_view<_CharT>;
+
+ static consteval
+ _String_view
+ _S_ftz() noexcept
+ { return _GLIBCXX_WIDEN("%F %T %Z"); }
+
+ static consteval
+ _String_view
+ _S_ft() noexcept
+ { return _S_ftz().substr(0, 5); }
+
+ static consteval
+ _String_view
+ _S_f() noexcept
+ { return _S_ftz().substr(0, 2); }
+
+ static consteval
+ _String_view
+ _S_t() noexcept
+ { return _S_ftz().substr(3, 2); }
+
+ static consteval
+ _String_view
+ _S_ymd() noexcept
+ { return _GLIBCXX_WIDEN("%Y/%b/%d"); }
+
+ static consteval
+ _String_view
+ _S_ym() noexcept
+ { return _S_ymd().substr(0, 5); }
+
+ static consteval
+ _String_view
+ _S_md() noexcept
+ { return _S_ymd().substr(3); }
+
+ static consteval
+ _String_view
+ _S_y() noexcept
+ { return _S_ymd().substr(0, 2); }
+
+ static consteval
+ _String_view
+ _S_m() noexcept
+ { return _S_ymd().substr(3, 2); }
+
+ static consteval
+ _String_view
+ _S_d() noexcept
+ { return _S_ymd().substr(6, 2); }
+
+ static consteval
+ _String_view
+ _S_ymwi() noexcept
+ // %\0 is extension for handling weekday index
+ { return _String_view(_GLIBCXX_WIDEN("%Y/%b/%a[%\0]"), 12); }
+
+ static consteval
+ _String_view
+ _S_mwi() noexcept
+ { return _S_ymwi().substr(3); }
+
+ static consteval
+ _String_view
+ _S_wi() noexcept
+ { return _S_ymwi().substr(6); }
+
+ static consteval
+ _String_view
+ _S_w() noexcept
+ { return _S_ymwi().substr(6, 2); }
+
+ static consteval
+ _String_view
+ _S_ymwl() noexcept
+ { return _GLIBCXX_WIDEN("%Y/%b/%a[last]"); }
+
+ static consteval
+ _String_view
+ _S_mwl() noexcept
+ { return _S_ymwl().substr(3); }
+
+ static consteval
+ _String_view
+ _S_wl() noexcept
+ { return _S_ymwl().substr(6); }
+
+ static consteval
+ _String_view
+ _S_yml() noexcept
+ { return _GLIBCXX_WIDEN("%Y/%b/last"); }
+
+ static consteval
+ _String_view
+ _S_ml() noexcept
+ { return _S_yml().substr(3); }
};
- constexpr _ChronoParts
- operator|(_ChronoParts __x, _ChronoParts __y) noexcept
- { return static_cast<_ChronoParts>((int)__x | (int)__y); }
+ template<typename _CharT>
+ struct _ChronoData
+ {
+ static constexpr unsigned _S_max_prec = 18;
+ using _Attoseconds = chrono::duration<__UINT_LEAST64_TYPE__, atto>;
+
+ using _FormatContext
+ = basic_format_context<_Sink_iter<_CharT>, _CharT>;
+ using _FormatArgs = basic_format_args<_FormatContext>;
+ static inline auto _S_args = std::make_format_args<_FormatContext>();
+
+ _ChronoData() = default;
+ _ChronoData(_ChronoData&&) = delete;
+
+ // time since epoch
+ chrono::seconds _M_eseconds;
+ // n.b. due offset being seconds or coarser, local and epoch subseconds
+ // has the same value
+ _Attoseconds _M_subseconds;
+ // _M_ereps.get(0) stores duration units
+ // _M_ereps.get(1) stores subseconds units
+ // _M_ereps.get(2) stores precision
+ _FormatArgs _M_ereps = _S_args;
+ basic_string_view<_CharT> _M_unit_suffix;
+
+ // local (wall) time
+ chrono::local_seconds _M_lseconds;
+ chrono::local_days _M_ldays;
+
+ chrono::year _M_year;
+ chrono::month _M_month;
+ chrono::day _M_day;
+ chrono::weekday _M_weekday;
+ unsigned char _M_weekday_index;
+ chrono::days _M_day_of_year;
+
+ bool _M_is_neg;
+ chrono::hours _M_hours;
+ chrono::minutes _M_minutes;
+ chrono::seconds _M_seconds;
+
+ chrono::seconds _M_zone_offset;
+ basic_string_view<_CharT> _M_zone_abbrev;
+ const char* _M_zone_cstr = "";
+
+ template<typename _YearMonth>
+ [[__gnu__::__always_inline__]]
+ _ChronoParts
+ _M_fill_year_month(const _YearMonth& __ym, _ChronoParts __parts)
+ {
+ _M_year = __ym.year();
+ __parts -= _ChronoParts::_Year;
+ _M_month = __ym.month();
+ __parts -= _ChronoParts::_Month;
+ return __parts;
+ }
- constexpr _ChronoParts&
- operator|=(_ChronoParts& __x, _ChronoParts __y) noexcept
- { return __x = __x | __y; }
+ [[__gnu__::__always_inline__]]
+ _ChronoParts
+ _M_fill_day(chrono::day __d, _ChronoParts __parts)
+ {
+ _M_day = __d;
+ __parts -= _ChronoParts::_Day;
+ _M_weekday_index = ((unsigned)__d + 6u) % 7u;
+ __parts -= _ChronoParts::_WeekdayIndex;
+ return __parts;
+ }
+
+ [[__gnu__::__always_inline__]]
+ _ChronoParts
+ _M_fill_weekday(chrono::weekday_indexed __wi, _ChronoParts __parts)
+ {
+ _M_weekday = __wi.weekday();
+ __parts -= _ChronoParts::_Weekday;
+ _M_weekday_index = __wi.index();
+ __parts -= _ChronoParts::_WeekdayIndex;
+ return __parts;
+ }
+
+ [[__gnu__::__always_inline__]]
+ _ChronoParts
+ _M_fill_aux(chrono::local_days __ld, _ChronoParts __parts)
+ {
+ using namespace chrono;
+ if ((__parts & _ChronoParts::_Weekday) != 0)
+ _M_weekday = weekday(__ld);
+ __parts -= _ChronoParts::_Weekday;
+ if ((__parts & _ChronoParts::_DayOfYear) != 0)
+ // See "Calculating Ordinal Dates" at
+ // https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes
+ _M_day_of_year = __ld - local_days(_M_year/January/0);
+ __parts -= _ChronoParts::_DayOfYear;
+ return __parts;
+ }
+
+ [[__gnu__::__always_inline__]]
+ _ChronoParts
+ _M_fill_ldays(chrono::local_days __ld, _ChronoParts __parts)
+ {
+ _M_ldays = __ld;
+ __parts -= _ChronoParts::_LocalDays;
+ return _M_fill_aux(__ld, __parts);
+ }
+
+ void
+ _M_fill_time(chrono::seconds __d)
+ {
+ chrono::hh_mm_ss<chrono::seconds> __hms(__d);
+ _M_hours = __hms.hours();
+ _M_minutes = __hms.minutes();
+ _M_seconds = __hms.seconds();
+ }
+
+ void
+ _M_fill_date_time(chrono::local_seconds __ls, _ChronoParts __parts)
+ {
+ _M_ldays = chrono::floor<chrono::days>(__ls);
+ __parts -= _ChronoParts::_LocalDays;
+ if ((__parts & _ChronoParts::_HoursMinutesSeconds) != 0)
+ _M_fill_time(_M_lseconds - _M_ldays);
+
+ if ((__parts & _ChronoParts::_Date) != 0)
+ {
+ const chrono::year_month_day __ymd(_M_ldays);
+ _M_fill_year_month(__ymd, __parts);
+ _M_fill_day(__ymd.day(), __parts);
+ _M_fill_aux(_M_ldays, __parts);
+ }
+ }
+
+ void
+ _M_fill_zone(const char* __abbrev, const wchar_t* __wabbrev)
+ {
+ if constexpr (is_same_v<_CharT, char>)
+ _M_zone_abbrev = __abbrev;
+ else
+ _M_zone_abbrev = __wabbrev;
+ _M_zone_cstr = __abbrev;
+ }
+
+ [[__gnu__::__always_inline__]]
+ void
+ _M_fill_utc_zone()
+ { _M_fill_zone("UTC", L"UTC"); }
+ };
// TODO rename this to chrono::__formatter? or chrono::__detail::__formatter?
template<typename _CharT>
@@ -251,14 +553,22 @@ namespace __format
using __string_view = basic_string_view<_CharT>;
using __string = basic_string<_CharT>;
+ __formatter_chrono() = default;
+
+ constexpr explicit
+ __formatter_chrono(_ChronoSpec<_CharT> __spec) noexcept
+ : _M_spec(__spec)
+ { }
+
template<typename _ParseContext>
constexpr typename _ParseContext::iterator
- _M_parse(_ParseContext& __pc, _ChronoParts __parts)
+ _M_parse(_ParseContext& __pc, _ChronoParts __parts,
+ const _ChronoSpec<_CharT>& __def)
{
auto __first = __pc.begin();
auto __last = __pc.end();
- _ChronoSpec<_CharT> __spec{};
+ _ChronoSpec<_CharT> __spec = __def;
auto __finalize = [this, &__spec] {
_M_spec = __spec;
@@ -284,13 +594,21 @@ namespace __format
if (__finished())
return __first;
- if (__parts & _ChronoParts::_Duration)
+ if (*__first == '.')
{
- __first = __spec._M_parse_precision(__first, __last, __pc);
- if (__finished())
- return __first;
+ if ((__parts & _ChronoParts::_EpochUnits) == 0
+ || !__spec._M_floating_point_rep)
+ __throw_format_error("format error: invalid precision for duration");
+
+ // Precision is allowed, but value is ignored.
+ __first = _Spec<_CharT>()._M_parse_precision(__first, __last, __pc);
+ // Still inditate that there was user supplied precision.
+ __spec._M_prec_kind = _WP_value;
+ if (__finished())
+ return __first;
}
+ __spec._M_localized = false;
__first = __spec._M_parse_locale(__first, __last);
if (__finished())
return __first;
@@ -312,6 +630,10 @@ namespace __format
// Parse chrono-specs in [first,last), checking each conversion-spec
// against __parts (so fail for %Y if no year in parts).
// Save range in __spec._M_chrono_specs.
+ __spec._M_debug = false;
+ __spec._M_locale_specific = false;
+ __spec._M_needed = _ChronoParts::_None;
+ __spec._M_chrono_specs = __string_view();
const auto __chrono_specs = __first++; // Skip leading '%'
if (*__chrono_specs != '%')
@@ -320,17 +642,18 @@ namespace __format
_CharT __mod{};
bool __conv = true;
- int __needed = 0;
- bool __locale_specific = false;
-
while (__first != __last)
{
enum _Mods { _Mod_none, _Mod_E, _Mod_O, _Mod_E_O };
_Mods __allowed_mods = _Mod_none;
+ _ChronoParts __needed = _ChronoParts::_None;
+ bool __locale_specific = false;
+
_CharT __c = *__first++;
switch (__c)
{
+ using enum _ChronoParts;
case 'a':
case 'A':
__needed = _Weekday;
@@ -343,7 +666,7 @@ namespace __format
__locale_specific = true;
break;
case 'c':
- __needed = _DateTime;
+ __needed = _Date|_HoursMinutesSeconds;
__allowed_mods = _Mod_E;
__locale_specific = true;
break;
@@ -358,27 +681,27 @@ namespace __format
break;
case 'D':
case 'F':
- __needed = _Date;
+ __needed = _YearMonthDay;
break;
case 'g':
case 'G':
- __needed = _Date;
+ __needed = _LocalDays|_Weekday;
break;
case 'H':
case 'I':
- __needed = _TimeOfDay;
+ __needed = _HoursMinutesSeconds;
__allowed_mods = _Mod_O;
break;
case 'j':
- if (!(__parts & _Duration))
- __needed = _Date;
+ __needed = __spec._M_time_only ? _HoursMinutesSeconds
+ : _DayOfYear;
break;
case 'm':
__needed = _Month;
__allowed_mods = _Mod_O;
break;
case 'M':
- __needed = _TimeOfDay;
+ __needed = _HoursMinutesSeconds;
__allowed_mods = _Mod_O;
break;
case 'p':
@@ -386,12 +709,16 @@ namespace __format
__locale_specific = true;
[[fallthrough]];
case 'R':
+ __needed = _HoursMinutesSeconds;
+ break;
case 'T':
__needed = _TimeOfDay;
break;
case 'q':
+ __needed = _UnitSuffix;
+ break;
case 'Q':
- __needed = _Duration;
+ __needed = _EpochUnits;
break;
case 'S':
__needed = _TimeOfDay;
@@ -405,7 +732,7 @@ namespace __format
case 'U':
case 'V':
case 'W':
- __needed = _Date;
+ __needed = _LocalDays|_Year|_DayOfYear|_Weekday;
__allowed_mods = _Mod_O;
break;
case 'x':
@@ -414,7 +741,7 @@ namespace __format
__allowed_mods = _Mod_E;
break;
case 'X':
- __needed = _TimeOfDay;
+ __needed = _HoursMinutesSeconds;
__locale_specific = true;
__allowed_mods = _Mod_E;
break;
@@ -427,11 +754,11 @@ namespace __format
__allowed_mods = _Mod_E;
break;
case 'z':
- __needed = _TimeZone;
+ __needed = _ZoneOffset;
__allowed_mods = _Mod_E_O;
break;
case 'Z':
- __needed = _TimeZone;
+ __needed = _ZoneAbbrev;
break;
case 'n':
case 't':
@@ -459,10 +786,16 @@ namespace __format
__locale_specific = true;
__mod = _CharT();
+ // localized formats do not include subseconds
+ if (__locale_specific)
+ __needed -= _ChronoParts::_Subseconds;
+
if ((__parts & __needed) != __needed)
__throw_format_error("chrono format error: format argument "
"does not contain the information "
"required by the chrono-specs");
+ __spec._M_needed |= __needed;
+ __spec._M_locale_specific |= __locale_specific;
// Scan for next '%', ignoring literal-chars before it.
size_t __pos = __string_view(__first, __last - __first).find('%');
@@ -488,33 +821,22 @@ namespace __format
_M_spec = __spec;
_M_spec._M_chrono_specs
= __string_view(__chrono_specs, __first - __chrono_specs);
- _M_spec._M_locale_specific(__locale_specific);
return __first;
}
- // TODO this function template is instantiated for every different _Tp.
- // Consider creating a polymorphic interface for calendar types so
- // that we instantiate fewer different specializations. Similar to
- // _Sink_iter for std::format. Replace each _S_year, _S_day etc. with
- // member functions of that type.
- template<typename _Tp, typename _FormatContext>
+ // pre: !_M_spec._M_chrono_specs.empty()
+ template<typename _FormatContext>
typename _FormatContext::iterator
- _M_format(const _Tp& __t, _FormatContext& __fc,
- bool __is_neg = false) const
+ _M_format(const _ChronoData<_CharT>& __t, _FormatContext& __fc) const
{
- auto __first = _M_spec._M_chrono_specs.begin();
- const auto __last = _M_spec._M_chrono_specs.end();
- if (__first == __last)
- return _M_format_to_ostream(__t, __fc, __is_neg);
-
#if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3565. Handling of encodings in localized formatting
// of chrono types is underspecified
if constexpr (is_same_v<_CharT, char>)
if constexpr (__unicode::__literal_encoding_is_utf8())
- if (_M_spec._M_localized && _M_spec._M_locale_specific())
+ if (_M_spec._M_localized && _M_spec._M_locale_specific)
{
extern locale __with_encoding_conversion(const locale&);
@@ -522,36 +844,119 @@ namespace __format
// in the locale's encoding to UTF-8.
locale __loc = __fc.locale();
if (__loc != locale::classic())
- __fc._M_loc = __with_encoding_conversion(__loc);
+ __fc._M_loc = __with_encoding_conversion(__loc);
}
#endif
- _Sink_iter<_CharT> __out;
- __format::_Str_sink<_CharT> __sink;
- bool __write_direct = false;
- if constexpr (is_same_v<typename _FormatContext::iterator,
- _Sink_iter<_CharT>>)
- {
- if (_M_spec._M_width_kind == __format::_WP_none)
+ const size_t __padwidth = _M_spec._M_get_width(__fc);
+ if (__padwidth == 0)
+ return _M_format_to(__t, __fc.out(), __fc);
+
+ using _Out = typename _FormatContext::iterator;
+ _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth);
+ _M_format_to(__t, __sink.out(), __fc);
+ return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill);
+ }
+
+
+ _ChronoSpec<_CharT> _M_spec;
+
+ protected:
+ static constexpr const _CharT* _S_chars
+ = _GLIBCXX_WIDEN("0123456789.Lf:/ +-{}");
+ static constexpr _CharT _S_dot = _S_chars[10];
+ static constexpr _CharT _S_colon = _S_chars[13];
+ static constexpr _CharT _S_slash = _S_chars[14];
+ static constexpr _CharT _S_space = _S_chars[15];
+ static constexpr const _CharT* _S_fp_fmt = _S_chars + 11;
+ static constexpr const _CharT* _S_plus_minus = _S_chars + 16;
+ static constexpr const _CharT* _S_minus_empty_spec = _S_chars + 17;
+ static constexpr const _CharT* _S_empty_spec = _S_chars + 18;
+
+ [[__gnu__::__always_inline__]]
+ static _Runtime_format_string<_CharT>
+ _S_empty_fs()
+ { return _Runtime_format_string<_CharT>(_S_empty_spec); }
+
+ // Return the formatting locale.
+ template<typename _FormatContext>
+ std::locale
+ _M_locale(_FormatContext& __fc) const
+ {
+ if (!_M_spec._M_localized)
+ return std::locale::classic();
+ else
+ return __fc.locale();
+ }
+
+ private:
+ template<typename _OutIter>
+ _OutIter
+ _M_write(_OutIter __out, const locale& __loc, __string_view __s) const
+ {
+#if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
+ __sso_string __buf;
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3565. Handling of encodings in localized formatting
+ // of chrono types is underspecified
+ if constexpr (is_same_v<_CharT, char>)
+ if constexpr (__unicode::__literal_encoding_is_utf8())
+ if (_M_spec._M_localized && _M_spec._M_locale_specific
+ && __loc != locale::classic())
{
- __out = __fc.out();
- __write_direct = true;
+ extern string_view
+ __locale_encoding_to_utf8(const locale&, string_view, void*);
+
+ __s = __locale_encoding_to_utf8(__loc, __s, &__buf);
}
- else
- __out = __sink.out();
- }
- else
- __out = __sink.out();
+#endif
+ return __format::__write(std::move(__out), __s);
+ }
- // formatter<duration> passes the correct value of __is_neg
- // for durations but for hh_mm_ss we decide it here.
- if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>)
- __is_neg = __t.is_negative();
+ [[__gnu__::__always_inline__]]
+ static bool
+ _S_localized_spec(_CharT __conv, _CharT __mod)
+ {
+ switch (__conv)
+ {
+ case 'c':
+ case 'r':
+ case 'x':
+ case 'X':
+ return true;
+ case 'z':
+ return false;
+ default:
+ return (bool)__mod;
+ };
+ }
- auto __print_sign = [&__is_neg, &__out] {
- if constexpr (chrono::__is_duration_v<_Tp>
- || __is_specialization_of<_Tp, chrono::hh_mm_ss>)
- if (__is_neg)
+ // Use the formatting locale's std::time_put facet to produce
+ // a locale-specific representation.
+ template<typename _Iter>
+ _Iter
+ _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm& __tm,
+ char __fmt, char __mod) const
+ {
+ basic_ostringstream<_CharT> __os;
+ __os.imbue(__loc);
+ const auto& __tp = use_facet<time_put<_CharT>>(__loc);
+ __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
+ if (__os)
+ __out = _M_write(std::move(__out), __loc, __os.view());
+ return __out;
+ }
+
+ template<typename _OutIter, typename _FormatContext>
+ _OutIter
+ _M_format_to(const _ChronoData<_CharT>& __t, _OutIter __out,
+ _FormatContext& __fc) const
+ {
+ auto __first = _M_spec._M_chrono_specs.begin();
+ const auto __last = _M_spec._M_chrono_specs.end();
+
+ auto __print_sign = [__is_neg = __t._M_is_neg, &__out] () mutable {
+ if (__is_neg)
{
*__out++ = _S_plus_minus[1];
__is_neg = false;
@@ -559,6 +964,36 @@ namespace __format
return std::move(__out);
};
+ struct tm __tm{};
+ bool __use_locale_fmt = false;
+ if (_M_spec._M_localized && _M_spec._M_locale_specific)
+ if (__fc.locale() != locale::classic())
+ {
+ __use_locale_fmt = true;
+
+ __tm.tm_year = (int)__t._M_year - 1900;
+ __tm.tm_yday = __t._M_day_of_year.count();
+ __tm.tm_mon = (unsigned)__t._M_month - 1;
+ __tm.tm_mday = (unsigned)__t._M_day;
+ __tm.tm_wday = __t._M_weekday.c_encoding();
+ __tm.tm_hour = __t._M_hours.count();
+ __tm.tm_min = __t._M_minutes.count();
+ __tm.tm_sec = __t._M_seconds.count();
+
+ // Some locales use %Z in their %c format but we don't want strftime
+ // to use the system's local time zone (from /etc/localtime or $TZ)
+ // as the output for %Z. Setting tm_isdst to -1 says there is no
+ // time zone info available for the time in __tm.
+ __tm.tm_isdst = -1;
+
+#ifdef _GLIBCXX_USE_STRUCT_TM_TM_ZONE
+ // POSIX.1-2024 adds tm.tm_zone which will be used for %Z.
+ // BSD has had tm_zone since 1987 but as char* so cast away const.
+ if (__t._M_zone_cstr)
+ __tm.tm_zone = const_cast<char*>(__t._M_zone_cstr);
+#endif
+ }
+
// Characters to output for "%n", "%t" and "%%" specifiers.
constexpr const _CharT* __literals = _GLIBCXX_WIDEN("\n\t%");
@@ -568,100 +1003,96 @@ namespace __format
do
{
_CharT __c = *__first++;
- switch (__c)
+ if (__use_locale_fmt && _S_localized_spec(__c, __mod)) [[unlikely]]
+ __out = _M_locale_fmt(std::move(__out), __fc.locale(),
+ __tm, __c, __mod);
+ else switch (__c)
{
+ // %\0 is extension for handling weekday index
+ case '\0':
+ __out = _M_wi(__t._M_weekday_index, std::move(__out));
+ break;
case 'a':
case 'A':
- __out = _M_a_A(__t, std::move(__out), __fc, __c == 'A');
+ __out = _M_a_A(__t._M_weekday, std::move(__out), __fc, __c == 'A');
break;
case 'b':
case 'h':
case 'B':
- __out = _M_b_B(__t, std::move(__out), __fc, __c == 'B');
+ __out = _M_b_B(__t._M_month, std::move(__out), __fc, __c == 'B');
break;
case 'c':
- __out = _M_c(__t, std::move(__out), __fc, __mod == 'E');
+ __out = _M_c(__t, std::move(__out), __fc);
break;
case 'C':
case 'y':
case 'Y':
- __out = _M_C_y_Y(__t, std::move(__out), __fc, __c, __mod);
+ __out = _M_C_y_Y(__t._M_year, std::move(__out), __c);
break;
case 'd':
case 'e':
- __out = _M_d_e(__t, std::move(__out), __fc, __c, __mod == 'O');
+ __out = _M_d_e(__t._M_day, std::move(__out), __c);
break;
case 'D':
- __out = _M_D(__t, std::move(__out), __fc);
+ case 'x':
+ __out = _M_D_x(__t, std::move(__out));
break;
case 'F':
- __out = _M_F(__t, std::move(__out), __fc);
+ __out = _M_F(__t, std::move(__out));
break;
case 'g':
case 'G':
- __out = _M_g_G(__t, std::move(__out), __fc, __c == 'G');
+ __out = _M_g_G(__t, std::move(__out), __c == 'G');
break;
case 'H':
case 'I':
- __out = _M_H_I(__t, __print_sign(), __fc, __c, __mod == 'O');
+ __out = _M_H_I(__t._M_hours, __print_sign(), __c);
break;
case 'j':
- __out = _M_j(__t, __print_sign(), __fc);
+ __out = _M_j(__t, __print_sign());
break;
case 'm':
- __out = _M_m(__t, std::move(__out), __fc, __mod == 'O');
+ __out = _M_m(__t._M_month, std::move(__out));
break;
case 'M':
- __out = _M_M(__t, __print_sign(), __fc, __mod == 'O');
+ __out = _M_M(__t._M_minutes, __print_sign());
break;
case 'p':
- __out = _M_p(__t, std::move(__out), __fc);
+ __out = _M_p(__t._M_hours, std::move(__out), __fc);
break;
case 'q':
- __out = _M_q(__t, std::move(__out), __fc);
+ __out = _M_q(__t._M_unit_suffix, std::move(__out));
break;
case 'Q':
- // %Q The duration's numeric value.
- if constexpr (chrono::__is_duration_v<_Tp>)
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 4118. How should duration formatters format custom rep?
- __out = std::format_to(__print_sign(), _S_empty_spec,
- +__t.count());
- else
- __throw_format_error("chrono format error: argument is "
- "not a duration");
+ __out = _M_Q(__t, __print_sign(), __fc);
break;
case 'r':
__out = _M_r(__t, __print_sign(), __fc);
break;
case 'R':
+ case 'X':
+ __out = _M_R_X(__t, __print_sign(), __c != 'R');
+ break;
case 'T':
- __out = _M_R_T(__t, __print_sign(), __fc, __c == 'T');
+ __out = _M_T(__t, __print_sign(), __fc);
break;
case 'S':
- __out = _M_S(__t, __print_sign(), __fc, __mod == 'O');
+ __out = _M_S(__t, __print_sign(), __fc, __mod != 'O');
break;
case 'u':
case 'w':
- __out = _M_u_w(__t, std::move(__out), __fc, __c, __mod == 'O');
+ __out = _M_u_w(__t._M_weekday, std::move(__out), __c);
break;
case 'U':
case 'V':
case 'W':
- __out = _M_U_V_W(__t, std::move(__out), __fc, __c,
- __mod == 'O');
- break;
- case 'x':
- __out = _M_x(__t, std::move(__out), __fc, __mod == 'E');
- break;
- case 'X':
- __out = _M_X(__t, __print_sign(), __fc, __mod == 'E');
+ __out = _M_U_V_W(__t, std::move(__out), __c);
break;
case 'z':
- __out = _M_z(__t, std::move(__out), __fc, (bool)__mod);
+ __out = _M_z(__t._M_zone_offset, std::move(__out), (bool)__mod);
break;
case 'Z':
- __out = _M_Z(__t, std::move(__out), __fc);
+ __out = _M_Z(__t._M_zone_abbrev, std::move(__out));
break;
case 'n':
*__out++ = __literals[0];
@@ -699,145 +1130,40 @@ namespace __format
}
}
while (__first != __last);
-
- if constexpr (is_same_v<typename _FormatContext::iterator,
- _Sink_iter<_CharT>>)
- if (__write_direct)
- return __out;
-
- auto __str = std::move(__sink).get();
- return __format::__write_padded_as_spec(__str, __str.size(),
- __fc, _M_spec);
+ return std::move(__out);
}
- _ChronoSpec<_CharT> _M_spec;
-
- private:
- // Return the formatting locale.
- template<typename _FormatContext>
- std::locale
- _M_locale(_FormatContext& __fc) const
- {
- if (!_M_spec._M_localized)
- return std::locale::classic();
- else
- return __fc.locale();
- }
-
- // Format for empty chrono-specs, e.g. "{}" (C++20 [time.format] p6).
- // TODO: consider moving body of every operator<< into this function
- // and use std::format("{}", t) to implement those operators. That
- // would avoid std::format("{}", t) calling operator<< which calls
- // std::format again.
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_format_to_ostream(const _Tp& __t, _FormatContext& __fc,
- bool __is_neg) const
- {
- using ::std::chrono::__detail::__utc_leap_second;
- using ::std::chrono::__detail::__local_time_fmt;
-
- basic_ostringstream<_CharT> __os;
- __os.imbue(_M_locale(__fc));
-
- if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
- {
- // Format as "{:L%F %T}"
- auto __days = chrono::floor<chrono::days>(__t._M_time);
- __os << chrono::year_month_day(__days) << ' '
- << chrono::hh_mm_ss(__t._M_time - __days);
-
- // For __local_time_fmt the __is_neg flags says whether to
- // append " %Z" to the result.
- if (__is_neg)
- {
- if (!__t._M_abbrev) [[unlikely]]
- __format::__no_timezone_available();
- else if constexpr (is_same_v<_CharT, char>)
- __os << ' ' << *__t._M_abbrev;
- else
- {
- __os << L' ';
- for (char __c : *__t._M_abbrev)
- __os << __c;
- }
- }
- }
- else
- {
- if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
- __os << __t._M_date << ' ' << __t._M_time;
- else if constexpr (chrono::__is_time_point_v<_Tp>)
- {
- // Need to be careful here because not all specializations
- // of chrono::sys_time can be written to an ostream.
- // For the specializations of time_point that can be
- // formatted with an empty chrono-specs, either it's a
- // sys_time with period greater or equal to days:
- if constexpr (is_convertible_v<_Tp, chrono::sys_days>)
- __os << _S_date(__t);
- else // Or it's formatted as "{:L%F %T}":
- {
- auto __days = chrono::floor<chrono::days>(__t);
- __os << chrono::year_month_day(__days) << ' '
- << chrono::hh_mm_ss(__t - __days);
- }
- }
- else
- {
- if constexpr (chrono::__is_duration_v<_Tp>)
- if (__is_neg) [[unlikely]]
- __os << _S_plus_minus[1];
- __os << __t;
- }
- }
-
- auto __str = std::move(__os).str();
- return __format::__write_padded_as_spec(__str, __str.size(),
- __fc, _M_spec);
- }
-
- static constexpr const _CharT* _S_chars
- = _GLIBCXX_WIDEN("0123456789+-:/ {}");
- static constexpr const _CharT* _S_plus_minus = _S_chars + 10;
- static constexpr _CharT _S_colon = _S_chars[12];
- static constexpr _CharT _S_slash = _S_chars[13];
- static constexpr _CharT _S_space = _S_chars[14];
- static constexpr const _CharT* _S_empty_spec = _S_chars + 15;
-
template<typename _OutIter>
_OutIter
- _M_write(_OutIter __out, const locale& __loc, __string_view __s) const
+ _M_wi(unsigned __wi, _OutIter __out) const
{
-#if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
- __sso_string __buf;
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 3565. Handling of encodings in localized formatting
- // of chrono types is underspecified
- if constexpr (is_same_v<_CharT, char>)
- if constexpr (__unicode::__literal_encoding_is_utf8())
- if (_M_spec._M_localized && _M_spec._M_locale_specific()
- && __loc != locale::classic())
- {
- extern string_view
- __locale_encoding_to_utf8(const locale&, string_view, void*);
-
- __s = __locale_encoding_to_utf8(__loc, __s, &__buf);
- }
-#endif
- return __format::__write(std::move(__out), __s);
+ // %\0 Extension to format weekday index, used only by empty format spec
+ _CharT __buf[3];
+ __out = __format::__write(std::move(__out), _S_str_d1(__buf, __wi));
+ if (_M_spec._M_debug && (__wi < 1 || __wi > 5))
+ __out = __format::__write(std::move(__out),
+ __string_view(_GLIBCXX_WIDEN(" is not a valid index")));
+ return std::move(__out);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_a_A(const _Tp& __t, typename _FormatContext::iterator __out,
+ template<typename _OutIter, typename _FormatContext>
+ _OutIter
+ _M_a_A(chrono::weekday __wd, _OutIter __out,
_FormatContext& __ctx, bool __full) const
{
// %a Locale's abbreviated weekday name.
// %A Locale's full weekday name.
- chrono::weekday __wd = _S_weekday(__t);
if (!__wd.ok())
- __throw_format_error("format error: invalid weekday");
+ {
+ if (!_M_spec._M_debug)
+ __throw_format_error("format error: invalid weekday");
+
+ _CharT __buf[3];
+ __out = __format::__write(std::move(__out),
+ _S_str_d1(__buf, __wd.c_encoding()));
+ return __format::__write(std::move(__out),
+ __string_view(_GLIBCXX_WIDEN(" is not a valid weekday")));
+ }
locale __loc = _M_locale(__ctx);
const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
@@ -850,16 +1176,25 @@ namespace __format
return _M_write(std::move(__out), __loc, __str);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_b_B(const _Tp& __t, typename _FormatContext::iterator __out,
+ template<typename _OutIter, typename _FormatContext>
+ _OutIter
+ _M_b_B(chrono::month __m, _OutIter __out,
_FormatContext& __ctx, bool __full) const
{
// %b Locale's abbreviated month name.
// %B Locale's full month name.
- chrono::month __m = _S_month(__t);
if (!__m.ok())
- __throw_format_error("format error: invalid month");
+ {
+ if (!_M_spec._M_debug)
+ __throw_format_error("format error: invalid month");
+
+ _CharT __buf[3];
+ __out = __format::__write(std::move(__out),
+ _S_str_d1(__buf, (unsigned)__m));
+ return __format::__write(std::move(__out),
+ __string_view(_GLIBCXX_WIDEN(" is not a valid month")));
+ }
+
locale __loc = _M_locale(__ctx);
const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
const _CharT* __months[12];
@@ -871,69 +1206,28 @@ namespace __format
return _M_write(std::move(__out), __loc, __str);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_c(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, bool __mod = false) const
+ template<typename _OutIter, typename _FormatContext>
+ _OutIter
+ _M_c(const _ChronoData<_CharT>& __t, _OutIter __out,
+ _FormatContext& __ctx) const
{
- // %c Locale's date and time representation.
- // %Ec Locale's alternate date and time representation.
-
- using namespace chrono;
- using ::std::chrono::__detail::__utc_leap_second;
- using ::std::chrono::__detail::__local_time_fmt;
-
- struct tm __tm{};
-
- // Some locales use %Z in their %c format but we don't want strftime
- // to use the system's local time zone (from /etc/localtime or $TZ)
- // as the output for %Z. Setting tm_isdst to -1 says there is no
- // time zone info available for the time in __tm.
- __tm.tm_isdst = -1;
-
-#ifdef _GLIBCXX_USE_STRUCT_TM_TM_ZONE
- // POSIX.1-2024 adds tm.tm_zone which will be used for %Z.
- // BSD has had tm_zone since 1987 but as char* so cast away const.
- if constexpr (__is_time_point_v<_Tp>)
- {
- // One of sys_time, utc_time, or local_time.
- if constexpr (!is_same_v<typename _Tp::clock, local_t>)
- __tm.tm_zone = const_cast<char*>("UTC");
- }
- else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
- {
- // local-time-format-t is used to provide time zone info for
- // one of zoned_time, tai_time, gps_time, or local_time.
- if (__t._M_abbrev)
- __tm.tm_zone = const_cast<char*>(__t._M_abbrev->c_str());
- }
- else
- __tm.tm_zone = const_cast<char*>("UTC");
-#endif
-
- auto __d = _S_days(__t); // Either sys_days or local_days.
- using _TDays = decltype(__d);
- const year_month_day __ymd(__d);
- const auto __y = __ymd.year();
- const auto __hms = _S_hms(__t);
-
- __tm.tm_year = (int)__y - 1900;
- __tm.tm_yday = (__d - _TDays(__y/January/1)).count();
- __tm.tm_mon = (unsigned)__ymd.month() - 1;
- __tm.tm_mday = (unsigned)__ymd.day();
- __tm.tm_wday = weekday(__d).c_encoding();
- __tm.tm_hour = __hms.hours().count();
- __tm.tm_min = __hms.minutes().count();
- __tm.tm_sec = __hms.seconds().count();
-
- return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm, 'c',
- __mod ? 'E' : '\0');
+ // %c Locale's date and time representation, for C-locale: %a %b %e %T %Y
+ // %Ec Locale's alternate date and time representation, for C-locale same as above
+
+ __out = _M_a_A(__t._M_weekday, std::move(__out), __ctx, false);
+ *__out = _S_space;
+ __out = _M_b_B(__t._M_month, std::move(++__out), __ctx, false);
+ *__out = _S_space;
+ __out = _M_d_e(__t._M_day, std::move(++__out), 'e');
+ *__out = _S_space;
+ __out = _M_R_X(__t, std::move(++__out), true);
+ *__out = _S_space;
+ return _M_C_y_Y(__t._M_year, std::move(++__out), 'Y');
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_C_y_Y(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, _CharT __conv, _CharT __mod = 0) const
+ template<typename _OutIter>
+ _OutIter
+ _M_C_y_Y(chrono::year __y, _OutIter __out, _CharT __conv) const
{
// %C Year divided by 100 using floored division.
// %EC Locale's alternative preresentation of the century (era name).
@@ -943,414 +1237,422 @@ namespace __format
// %Y Year as a decimal number.
// %EY Locale's alternative full year representation.
- chrono::year __y = _S_year(__t);
-
- if (__mod && _M_spec._M_localized) [[unlikely]]
- if (auto __loc = __ctx.locale(); __loc != locale::classic())
- {
- struct tm __tm{};
- __tm.tm_year = (int)__y - 1900;
- return _M_locale_fmt(std::move(__out), __loc, __tm,
- __conv, __mod);
- }
-
- basic_string<_CharT> __s;
int __yi = (int)__y;
const bool __is_neg = __yi < 0;
__yi = __builtin_abs(__yi);
+ int __ci = __yi / 100;
+ // For floored division -123//100 is -2 and -100//100 is -1
+ if (__conv == 'C' && __is_neg && (__ci * 100) != __yi) [[unlikely]]
+ ++__ci;
- if (__conv == 'Y' || __conv == 'C')
+ if (__conv != 'y' && __ci >= 100) [[unlikely]]
{
- int __ci = __yi / 100;
- if (__is_neg) [[unlikely]]
+ using _FmtStr = _Runtime_format_string<_CharT>;
+ __string_view __fs = _S_minus_empty_spec + !__is_neg;
+ __out = std::format_to(std::move(__out), _FmtStr(__fs),
+ __conv == 'C' ? __ci : __yi);
+ }
+ else
+ {
+ _CharT __buf[5];
+ __buf[0] = _S_plus_minus[1];
+ __string_view __sv(__buf + 3, __buf + 3);
+ if (__conv != 'y')
{
- __s.assign(1, _S_plus_minus[1]);
- // For floored division -123//100 is -2 and -100//100 is -1
- if (__conv == 'C' && (__ci * 100) != __yi)
- ++__ci;
+ _S_fill_two_digits(__buf + 1, __ci);
+ __sv = __string_view(__buf + !__is_neg, __buf + 3);
}
- if (__ci >= 100) [[unlikely]]
+ if (__conv != 'C')
{
- __s += std::format(_S_empty_spec, __ci / 100);
- __ci %= 100;
+ _S_fill_two_digits(__buf + 3, __yi % 100);
+ __sv = __string_view(__sv.data(), __buf + 5);
}
- __s += _S_two_digits(__ci);
+ __out = __format::__write(std::move(__out), __sv);
}
- if (__conv == 'Y' || __conv == 'y')
- __s += _S_two_digits(__yi % 100);
-
- return __format::__write(std::move(__out), __string_view(__s));
+ if (_M_spec._M_debug && __conv == 'Y' && !__y.ok()) [[unlikely]]
+ __out = __format::__write(std::move(__out),
+ __string_view(_GLIBCXX_WIDEN(" is not a valid year")));
+ return __out;
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_D(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext&) const
+ template<typename _OutIter>
+ _OutIter
+ _M_D_x(const _ChronoData<_CharT>& __t, _OutIter __out) const
{
- auto __ymd = _S_date(__t);
- basic_string<_CharT> __s;
-#if ! _GLIBCXX_USE_CXX11_ABI
- __s.reserve(8);
-#endif
- __s = _S_two_digits((unsigned)__ymd.month());
- __s += _S_slash;
- __s += _S_two_digits((unsigned)__ymd.day());
- __s += _S_slash;
- __s += _S_two_digits(__builtin_abs((int)__ymd.year()) % 100);
- return __format::__write(std::move(__out), __string_view(__s));
+ // %D Equivalent to %m/%d/%y
+ // %x Locale's date rep, for C-locale: %m/%d/%y
+ // %Ex Locale's alternative date representation, for C-locale same as above
+
+ auto __di = (unsigned)__t._M_day;
+ auto __mi = (unsigned)__t._M_month;
+ auto __yi = __builtin_abs((int)__t._M_year) % 100;
+
+ if (__mi >= 100 || __di >= 100) [[unlikely]]
+ {
+ using _FmtStr = _Runtime_format_string<_CharT>;
+ __string_view __fs = _GLIBCXX_WIDEN("{:02d}/{:02d}/{:02d}");
+ __out = std::format_to(std::move(__out), _FmtStr(__fs),
+ __mi, __di, __yi);
+ }
+ else
+ {
+ _CharT __buf[8];
+ __buf[2] = _S_slash;
+ __buf[5] = _S_slash;
+ __string_view __sv(__buf, __buf + 8);
+
+ _S_fill_two_digits(__buf, __mi);
+ _S_fill_two_digits(__buf + 3, __di);
+ _S_fill_two_digits(__buf + 6, __yi);
+ __out = __format::__write(std::move(__out), __sv);
+ }
+ return std::move(__out);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_d_e(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
+ template<typename _OutIter>
+ _OutIter
+ _M_d_e(chrono::day __d, _OutIter __out, _CharT __conv) const
{
// %d The day of month as a decimal number.
// %Od Locale's alternative representation.
// %e Day of month as decimal number, padded with space.
// %Oe Locale's alternative digits.
- chrono::day __d = _S_day(__t);
unsigned __i = (unsigned)__d;
- if (__mod && _M_spec._M_localized) [[unlikely]]
- if (auto __loc = __ctx.locale(); __loc != locale::classic())
- {
- struct tm __tm{};
- __tm.tm_mday = __i;
- return _M_locale_fmt(std::move(__out), __loc, __tm,
- (char)__conv, 'O');
- }
-
- auto __sv = _S_two_digits(__i);
- _CharT __buf[2];
+ _CharT __buf[3];
+ auto __sv = _S_str_d2(__buf, __i);
if (__conv == _CharT('e') && __i < 10)
{
- __buf[0] = _S_space;
__buf[1] = __sv[1];
+ __buf[0] = _S_space;
__sv = {__buf, 2};
}
- return __format::__write(std::move(__out), __sv);
+
+ __out = __format::__write(std::move(__out), __sv);
+ if (_M_spec._M_debug && !__d.ok()) [[unlikely]]
+ __out = __format::__write(std::move(__out),
+ __string_view(_GLIBCXX_WIDEN(" is not a valid day")));
+ return std::move(__out);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_F(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext&) const
+ template<typename _OutIter>
+ _OutIter
+ _M_F(const _ChronoData<_CharT>& __t, _OutIter __out) const
{
- auto __ymd = _S_date(__t);
- auto __s = std::format(_GLIBCXX_WIDEN("{:04d}- - "),
- (int)__ymd.year());
- auto __sv = _S_two_digits((unsigned)__ymd.month());
- __s[__s.size() - 5] = __sv[0];
- __s[__s.size() - 4] = __sv[1];
- __sv = _S_two_digits((unsigned)__ymd.day());
- __s[__s.size() - 2] = __sv[0];
- __s[__s.size() - 1] = __sv[1];
- __sv = __s;
- return __format::__write(std::move(__out), __sv);
+ auto __di = (unsigned)__t._M_day;
+ auto __mi = (unsigned)__t._M_month;
+ auto __yi = (int)__t._M_year;
+ const bool __is_neg = __yi < 0;
+ __yi = __builtin_abs(__yi);
+
+ if (__yi >= 10000 || __mi >= 100 || __di >= 100) [[unlikely]]
+ {
+ using _FmtStr = _Runtime_format_string<_CharT>;
+ __string_view __fs
+ = _GLIBCXX_WIDEN("-{:04d}-{:02d}-{:02d}") + !__is_neg;
+ __out = std::format_to(std::move(__out), _FmtStr(__fs),
+ __yi, __mi, __di);
+ }
+ else
+ {
+ _CharT __buf[11];
+ __buf[0] = _S_plus_minus[1];
+ __buf[5] = _S_plus_minus[1];
+ __buf[8] = _S_plus_minus[1];
+ __string_view __sv(__buf + !__is_neg, __buf + 11);
+
+ _S_fill_two_digits(__buf + 1, __yi / 100);
+ _S_fill_two_digits(__buf + 3, __yi % 100);
+ _S_fill_two_digits(__buf + 6, __mi);
+ _S_fill_two_digits(__buf + 9, __di);
+ __out = __format::__write(std::move(__out), __sv);
+ }
+
+ if (_M_spec._M_debug && !(__t._M_year/__t._M_month/__t._M_day).ok())
+ __out = __format::__write(std::move(__out),
+ __string_view(_GLIBCXX_WIDEN(" is not a valid date")));
+ return std::move(__out);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_g_G(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, bool __full) const
+ template<typename _OutIter>
+ _OutIter
+ _M_g_G(const _ChronoData<_CharT>& __t, _OutIter __out,
+ bool __full) const
{
// %g last two decimal digits of the ISO week-based year.
// %G ISO week-based year.
using namespace chrono;
- auto __d = _S_days(__t);
+ auto __d = __t._M_ldays;
// Move to nearest Thursday:
- __d -= (weekday(__d) - Monday) - days(3);
+ __d -= (__t._M_weekday - Monday) - days(3);
// ISO week-based year is the year that contains that Thursday:
year __y = year_month_day(__d).year();
- return _M_C_y_Y(__y, std::move(__out), __ctx, "yY"[__full]);
+ return _M_C_y_Y(__y, std::move(__out), "yY"[__full]);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_H_I(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
+ template<typename _OutIter>
+ _OutIter
+ _M_H_I(chrono::hours __h, _OutIter __out, _CharT __conv) const
{
// %H The hour (24-hour clock) as a decimal number.
// %OH Locale's alternative representation.
// %I The hour (12-hour clock) as a decimal number.
// %OI Locale's alternative representation.
- const auto __hms = _S_hms(__t);
- int __i = __hms.hours().count();
-
- if (__mod && _M_spec._M_localized) [[unlikely]]
- if (auto __loc = __ctx.locale(); __loc != locale::classic())
- {
- struct tm __tm{};
- __tm.tm_hour = __i;
- return _M_locale_fmt(std::move(__out), __loc, __tm,
- (char)__conv, 'O');
- }
+ int __i = __h.count();
if (__conv == _CharT('I'))
{
+ __i %= 12;
if (__i == 0)
__i = 12;
- else if (__i > 12)
- __i -= 12;
}
+ else if (__i >= 100) [[unlikely]]
+ return std::format_to(std::move(__out), _S_empty_fs(), __i);
+
return __format::__write(std::move(__out), _S_two_digits(__i));
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_j(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext&) const
+ template<typename _OutIter>
+ _OutIter
+ _M_j(const _ChronoData<_CharT>& __t, _OutIter __out) const
{
- if constexpr (chrono::__is_duration_v<_Tp>)
- {
- // Decimal number of days, without padding.
- unsigned __d = chrono::duration_cast<chrono::days>(__t).count();
- return std::format_to(std::move(__out), _S_empty_spec, __d);
- }
- else
- {
- // Day of the year as a decimal number, padding with zero.
- using namespace chrono;
- auto __day = _S_days(__t);
- auto __ymd = _S_date(__t);
- days __d;
- // See "Calculating Ordinal Dates" at
- // https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes
- if constexpr (is_same_v<typename decltype(__day)::clock, local_t>)
- __d = __day - local_days(__ymd.year()/January/0);
- else
- __d = __day - sys_days(__ymd.year()/January/0);
- return std::format_to(std::move(__out), _GLIBCXX_WIDEN("{:03d}"),
- __d.count());
- }
+ if (_M_spec._M_time_only)
+ {
+ // Decimal number of days, without padding.
+ auto __d = chrono::floor<chrono::days>(__t._M_hours).count();
+ return std::format_to(std::move(__out), _S_empty_fs(), __d);
+ }
+
+ auto __d = __t._M_day_of_year.count();
+ if (__d >= 1000) [[unlikely]]
+ return std::format_to(std::move(__out), _S_empty_fs(), __d);
+
+ _CharT __buf[3];
+ return __format::__write(std::move(__out), _S_str_d3(__buf, __d));
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_m(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, bool __mod) const
+ template<typename _OutIter>
+ _OutIter
+ _M_m(chrono::month __m, _OutIter __out) const
{
// %m month as a decimal number.
// %Om Locale's alternative representation.
- auto __m = _S_month(__t);
auto __i = (unsigned)__m;
- if (__mod && _M_spec._M_localized) [[unlikely]] // %Om
- if (auto __loc = __ctx.locale(); __loc != locale::classic())
- {
- struct tm __tm{};
- __tm.tm_mon = __i - 1;
- return _M_locale_fmt(std::move(__out), __loc, __tm,
- 'm', 'O');
- }
-
- return __format::__write(std::move(__out), _S_two_digits(__i));
+ _CharT __buf[3];
+ return __format::__write(std::move(__out), _S_str_d2(__buf, __i));
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_M(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, bool __mod) const
+ template<typename _OutIter>
+ _OutIter
+ _M_M(chrono::minutes __m, _OutIter __out) const
{
// %M The minute as a decimal number.
// %OM Locale's alternative representation.
- auto __m = _S_hms(__t).minutes();
auto __i = __m.count();
-
- if (__mod && _M_spec._M_localized) [[unlikely]] // %OM
- if (auto __loc = __ctx.locale(); __loc != locale::classic())
- {
- struct tm __tm{};
- __tm.tm_min = __i;
- return _M_locale_fmt(std::move(__out), __loc, __tm,
- 'M', 'O');
- }
-
return __format::__write(std::move(__out), _S_two_digits(__i));
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_p(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx) const
+ template<typename _OutIter, typename _FormatContext>
+ _OutIter
+ _M_p(chrono::hours __h, _OutIter __out, _FormatContext& __ctx) const
{
// %p The locale's equivalent of the AM/PM designations.
- auto __hms = _S_hms(__t);
+ auto __hi = __h.count();
+ if (__hi >= 24) [[unlikely]]
+ __hi %= 24;
+
locale __loc = _M_locale(__ctx);
const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
const _CharT* __ampm[2];
__tp._M_am_pm(__ampm);
- return _M_write(std::move(__out), __loc,
- __ampm[__hms.hours().count() >= 12]);
+ return _M_write(std::move(__out), __loc, __ampm[__hi >= 12]);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_q(const _Tp&, typename _FormatContext::iterator __out,
- _FormatContext&) const
+ template<typename _OutIter>
+ _OutIter
+ _M_q(__string_view __us, _OutIter __out) const
{
// %q The duration's unit suffix
- if constexpr (!chrono::__is_duration_v<_Tp>)
- __throw_format_error("format error: argument is not a duration");
- else
- {
- namespace __d = chrono::__detail;
- using period = typename _Tp::period;
- return __d::__fmt_units_suffix<period, _CharT>(std::move(__out));
- }
+ return __format::__write(std::move(__out), __us);
}
- // %Q handled in _M_format
+ template<typename _OutIter, typename _FormatContext>
+ _OutIter
+ _M_Q(const _ChronoData<_CharT>& __t, _OutIter __out,
+ _FormatContext&) const
+ {
+ // %Q The duration's numeric value.
+ return std::vformat_to(std::move(__out), _S_empty_spec, __t._M_ereps);
+ }
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_r(const _Tp& __tt, typename _FormatContext::iterator __out,
+ template<typename _OutIter, typename _FormatContext>
+ _OutIter
+ _M_r(const _ChronoData<_CharT>& __t, _OutIter __out,
_FormatContext& __ctx) const
{
- // %r locale's 12-hour clock time.
- auto __t = _S_floor_seconds(__tt);
- locale __loc = _M_locale(__ctx);
- const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
- const _CharT* __ampm_fmt;
- __tp._M_am_pm_format(&__ampm_fmt);
- basic_string<_CharT> __fmt(_S_empty_spec);
- __fmt.insert(1u, 1u, _S_colon);
- __fmt.insert(2u, __ampm_fmt);
- using _FmtStr = _Runtime_format_string<_CharT>;
- return _M_write(std::move(__out), __loc,
- std::format(__loc, _FmtStr(__fmt), __t));
+ // %r Locale's 12-hour clock time, for C-locale: %I:%M:%S %p
+ auto __hi = __t._M_hours.count() % 12;
+ if (__hi == 0)
+ __hi = 12;
+
+ _CharT __buf[9];
+ __buf[2] = _S_colon;
+ __buf[5] = _S_colon;
+ __buf[8] = _S_space;
+ _S_fill_two_digits(__buf, __hi);
+ _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
+ _S_fill_two_digits(__buf + 6, __t._M_seconds.count());
+
+ __string_view __sv(__buf, 9);
+ __out = __format::__write(std::move(__out), __sv);
+ return _M_p(__t._M_hours, std::move(__out), __ctx);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_R_T(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, bool __secs) const
+ template<typename _OutIter>
+ _OutIter
+ _M_R_X(const _ChronoData<_CharT>& __t, _OutIter __out,
+ bool __secs) const
{
- // %R Equivalent to %H:%M
- // %T Equivalent to %H:%M:%S
- auto __hms = _S_hms(__t);
-
- auto __s = std::format(_GLIBCXX_WIDEN("{:02d}:00"),
- __hms.hours().count());
- auto __sv = _S_two_digits(__hms.minutes().count());
- __s[__s.size() - 2] = __sv[0];
- __s[__s.size() - 1] = __sv[1];
- __sv = __s;
- __out = __format::__write(std::move(__out), __sv);
- if (__secs)
+ // %R Equivalent to %H:%M
+ // %X Locale's time rep, for C-locale: %H:%M:%S (without subseconds)
+ // %EX Locale's alternative time representation, for C-locale same as above
+
+ auto __hi = __t._M_hours.count();
+
+ _CharT __buf[8];
+ __buf[2] = _S_colon;
+ __buf[5] = _S_colon;
+ __string_view __sv(__buf, 8);
+
+ if (__hi >= 100) [[unlikely]]
{
- *__out++ = _S_colon;
- __out = _M_S(__hms, std::move(__out), __ctx);
+ __out = std::format_to(std::move(__out), _S_empty_fs(), __hi);
+ __sv.remove_prefix(2);
}
- return __out;
+ else
+ _S_fill_two_digits(__buf, __hi);
+
+ _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
+ if (__secs)
+ _S_fill_two_digits(__buf + 6, __t._M_seconds.count());
+ else
+ __sv.remove_suffix(3);
+
+ return __format::__write(std::move(__out), __sv);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_S(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, bool __mod = false) const
+ template<typename _OutIter, typename _FormatContext>
+ _OutIter
+ _M_S(const _ChronoData<_CharT>& __t, _OutIter __out,
+ _FormatContext& __ctx, bool __subs = true) const
{
// %S Seconds as a decimal number.
// %OS The locale's alternative representation.
- auto __hms = _S_hms(__t);
- auto __s = __hms.seconds();
+ auto __s = __t._M_seconds;
- if (__mod) [[unlikely]] // %OS
- {
- if (_M_spec._M_localized)
- if (auto __loc = __ctx.locale(); __loc != locale::classic())
- {
- struct tm __tm{};
- __tm.tm_sec = (int)__s.count();
- return _M_locale_fmt(std::move(__out), __loc, __tm,
- 'S', 'O');
- }
+ __out = __format::__write(std::move(__out),
+ _S_two_digits(__s.count()));
+ if (__subs)
+ __out = _M_subsecs(__t, std::move(__out), __ctx);
+ return __out;
+ }
- // %OS formats don't include subseconds, so just format that:
- return __format::__write(std::move(__out),
- _S_two_digits(__s.count()));
+ template<typename _OutIter, typename _FormatContext>
+ _OutIter
+ _M_subsecs(const _ChronoData<_CharT>& __t, _OutIter __out,
+ _FormatContext& __ctx) const
+ {
+ unsigned __prec = _M_spec._M_prec_kind != _WP_none
+ ? _M_spec._M_get_precision(__ctx)
+ : _M_spec._M_prec;
+ if (__prec == 0)
+ return __out;
+
+ _CharT __dot = _S_dot;
+ if (_M_spec._M_localized)
+ if (auto __loc = __ctx.locale(); __loc != locale::classic())
+ {
+ const auto& __np = use_facet<numpunct<_CharT>>(__loc);
+ __dot = __np.decimal_point();
}
+ *__out = __dot;
+ ++__out;
- if constexpr (__hms.fractional_width == 0)
- __out = __format::__write(std::move(__out),
- _S_two_digits(__s.count()));
- else
+ if (_M_spec._M_floating_point_rep)
{
- locale __loc = _M_locale(__ctx);
- auto __ss = __hms.subseconds();
- using rep = typename decltype(__ss)::rep;
- if constexpr (is_floating_point_v<rep>)
- {
- chrono::duration<rep> __fs = __s + __ss;
- __out = std::format_to(std::move(__out), __loc,
- _GLIBCXX_WIDEN("{:#0{}.{}Lf}"),
- __fs.count(),
- 3 + __hms.fractional_width,
- __hms.fractional_width);
- }
+ _Str_sink<_CharT> __sink;
+ if (_M_spec._M_localized && _M_spec._M_custom_rep)
+ std::vformat_to(__sink.out(), _M_locale(__ctx),
+ _GLIBCXX_WIDEN("{1:0.{2}Lf}"), __t._M_ereps);
else
- {
- const auto& __np
- = use_facet<numpunct<_CharT>>(__loc);
- __out = __format::__write(std::move(__out),
- _S_two_digits(__s.count()));
- *__out++ = __np.decimal_point();
- if constexpr (is_integral_v<rep>)
- __out = std::format_to(std::move(__out),
- _GLIBCXX_WIDEN("{:0{}}"),
- __ss.count(),
- __hms.fractional_width);
- else
- {
- auto __str = std::format(_S_empty_spec, __ss.count());
- __out = std::format_to(_GLIBCXX_WIDEN("{:0>{}s}"),
- __str,
- __hms.fractional_width);
- }
- }
+ std::vformat_to(__sink.out(),
+ _GLIBCXX_WIDEN("{1:0.{2}f}"), __t._M_ereps);
+
+ auto __sv = __sink.view();
+ // Skip leading zero and dot
+ __sv.remove_prefix(2);
+ return __format::__write(std::move(__out), __sv);
}
- return __out;
+
+ constexpr unsigned __max_prec = _ChronoData<_CharT>::_S_max_prec;
+ constexpr typename _ChronoData<_CharT>::_Attoseconds::rep __pow10t[]
+ {
+ 1u,
+ 10u, 100u, 1000u,
+ 10'000u, 100'000u, 1000'000u,
+ 10'000'000u, 100'000'000u, 1000'000'000u,
+ 10'000'000'000u, 100'000'000'000u, 1000'000'000'000u,
+ 10'000'000'000'000u, 100'000'000'000'000u, 1000'000'000'000'000u,
+ 10'000'000'000'000'000u, 100'000'000'000'000'000u, 1000'000'000'000'000'000u,
+ };
+
+ auto __subs = __t._M_subseconds.count();
+ if (__prec < __max_prec)
+ __subs /= __pow10t[__max_prec - __prec];
+ else if (__prec > __max_prec)
+ __prec = __max_prec;
+
+ using _FmtStr = _Runtime_format_string<_CharT>;
+ return std::format_to(__out, _FmtStr(_GLIBCXX_WIDEN("{0:0{1}}")),
+ __subs, __prec);
}
// %t handled in _M_format
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_u_w(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
+ template<typename _OutIter, typename _FormatContext>
+ _OutIter
+ _M_T(const _ChronoData<_CharT>& __t, _OutIter __out,
+ _FormatContext& __ctx) const
+ {
+ // %T Equivalent to %H:%M:%S, with subseconds
+ __out = _M_R_X(__t, std::move(__out), true);
+ return _M_subsecs(__t, std::move(__out), __ctx);
+ }
+
+ template<typename _OutIter>
+ _OutIter
+ _M_u_w(chrono::weekday __wd, _OutIter __out, _CharT __conv) const
{
// %u ISO weekday as a decimal number (1-7), where Monday is 1.
// %Ou Locale's alternative numeric rep.
// %w Weekday as a decimal number (0-6), where Sunday is 0.
// %Ow Locale's alternative numeric rep.
-
- chrono::weekday __wd = _S_weekday(__t);
-
- if (__mod && _M_spec._M_localized) [[unlikely]]
- if (auto __loc = __ctx.locale(); __loc != locale::classic())
- {
- struct tm __tm{};
- __tm.tm_wday = __wd.c_encoding();
- return _M_locale_fmt(std::move(__out), __loc, __tm,
- (char)__conv, 'O');
- }
-
unsigned __wdi = __conv == 'u' ? __wd.iso_encoding()
: __wd.c_encoding();
- const _CharT __d = _S_digit(__wdi);
- return __format::__write(std::move(__out), __string_view(&__d, 1));
+ _CharT __buf[3];
+ return __format::__write(std::move(__out), _S_str_d1(__buf, __wdi));
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_U_V_W(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
+ template<typename _OutIter>
+ _OutIter
+ _M_U_V_W(const _ChronoData<_CharT>& __t, _OutIter __out,
+ _CharT __conv) const
{
// %U Week number of the year as a decimal number, from first Sunday.
// %OU Locale's alternative numeric rep.
@@ -1359,182 +1661,64 @@ namespace __format
// %W Week number of the year as a decimal number, from first Monday.
// %OW Locale's alternative numeric rep.
using namespace chrono;
- auto __d = _S_days(__t);
- using _TDays = decltype(__d); // Either sys_days or local_days.
-
- if (__mod && _M_spec._M_localized) [[unlikely]]
- if (auto __loc = __ctx.locale(); __loc != locale::classic())
- {
- const year_month_day __ymd(__d);
- const year __y = __ymd.year();
- struct tm __tm{};
- __tm.tm_year = (int)__y - 1900;
- __tm.tm_yday = (__d - _TDays(__y/January/1)).count();
- __tm.tm_wday = weekday(__d).c_encoding();
- return _M_locale_fmt(std::move(__out), __loc, __tm,
- (char)__conv, 'O');
- }
- _TDays __first; // First day of week 1.
+ auto __d = __t._M_ldays;
+ local_days __first; // First day of week 1.
if (__conv == 'V') // W01 begins on Monday before first Thursday.
{
// Move to nearest Thursday:
- __d -= (weekday(__d) - Monday) - days(3);
+ __d -= (__t._M_weekday - Monday) - days(3);
// ISO week of __t is number of weeks since January 1 of the
// same year as that nearest Thursday.
- __first = _TDays(year_month_day(__d).year()/January/1);
+ __first = local_days(year_month_day(__d).year()/January/1);
}
else
{
- year __y;
- if constexpr (requires { __t.year(); })
- __y = __t.year();
- else
- __y = year_month_day(__d).year();
const weekday __weekstart = __conv == 'U' ? Sunday : Monday;
- __first = _TDays(__y/January/__weekstart[1]);
+ __first = local_days(__t._M_year/January/__weekstart[1]);
}
auto __weeks = chrono::floor<weeks>(__d - __first);
__string_view __sv = _S_two_digits(__weeks.count() + 1);
return __format::__write(std::move(__out), __sv);
}
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_x(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, bool __mod = false) const
- {
- // %x Locale's date rep
- // %Ex Locale's alternative date representation.
- locale __loc = _M_locale(__ctx);
- const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
- const _CharT* __date_reps[2];
- __tp._M_date_formats(__date_reps);
- const _CharT* __rep = __date_reps[__mod];
- if (!*__rep)
- return _M_D(__t, std::move(__out), __ctx);
-
- basic_string<_CharT> __fmt(_S_empty_spec);
- __fmt.insert(1u, 1u, _S_colon);
- __fmt.insert(2u, __rep);
- using _FmtStr = _Runtime_format_string<_CharT>;
- return _M_write(std::move(__out), __loc,
- std::format(__loc, _FmtStr(__fmt), __t));
- }
-
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_X(const _Tp& __tt, typename _FormatContext::iterator __out,
- _FormatContext& __ctx, bool __mod = false) const
- {
- // %X Locale's time rep
- // %EX Locale's alternative time representation.
- auto __t = _S_floor_seconds(__tt);
- locale __loc = _M_locale(__ctx);
- const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
- const _CharT* __time_reps[2];
- __tp._M_time_formats(__time_reps);
- const _CharT* __rep = __time_reps[__mod];
- if (!*__rep)
- return _M_R_T(__t, std::move(__out), __ctx, true);
-
- basic_string<_CharT> __fmt(_S_empty_spec);
- __fmt.insert(1u, 1u, _S_colon);
- __fmt.insert(2u, __rep);
- using _FmtStr = _Runtime_format_string<_CharT>;
- return _M_write(std::move(__out), __loc,
- std::format(__loc, _FmtStr(__fmt), __t));
- }
-
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_z(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext&, bool __mod = false) const
+ template<typename _OutIter>
+ _OutIter
+ _M_z(chrono::seconds __ts, _OutIter __out, bool __mod = false) const
{
- using ::std::chrono::__detail::__utc_leap_second;
- using ::std::chrono::__detail::__local_time_fmt;
-
- auto __utc = __mod ? __string_view(_GLIBCXX_WIDEN("+00:00"), 6)
- : __string_view(_GLIBCXX_WIDEN("+0000"), 5);
-
- if constexpr (chrono::__is_time_point_v<_Tp>)
+ if (__ts == 0s)
{
- if constexpr (is_same_v<typename _Tp::clock,
- chrono::system_clock>)
- return __format::__write(std::move(__out), __utc);
+ __string_view __zero
+ = __mod ? _GLIBCXX_WIDEN("+00:00") : _GLIBCXX_WIDEN("+0000");
+ return __format::__write(std::move(__out), __zero);
}
- else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
- {
- if (__t._M_offset_sec)
- {
- auto __sv = __utc;
- basic_string<_CharT> __s;
- if (*__t._M_offset_sec != 0s)
- {
- chrono:: hh_mm_ss __hms(*__t._M_offset_sec);
- __s = _S_plus_minus[__hms.is_negative()];
- __s += _S_two_digits(__hms.hours().count());
- if (__mod)
- __s += _S_colon;
- __s += _S_two_digits(__hms.minutes().count());
- __sv = __s;
- }
- return __format::__write(std::move(__out), __sv);
- }
- }
- else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
- return __format::__write(std::move(__out), __utc);
-
- __no_timezone_available();
- }
- template<typename _Tp, typename _FormatContext>
- typename _FormatContext::iterator
- _M_Z(const _Tp& __t, typename _FormatContext::iterator __out,
- _FormatContext& __ctx) const
- {
- using ::std::chrono::__detail::__utc_leap_second;
- using ::std::chrono::__detail::__local_time_fmt;
+ chrono::hh_mm_ss<chrono::seconds> __hms(__ts);
+ unsigned __mo = 3 + __mod;
- __string_view __utc(_GLIBCXX_WIDEN("UTC"), 3);
- if constexpr (chrono::__is_time_point_v<_Tp>)
- {
- if constexpr (is_same_v<typename _Tp::clock,
- chrono::system_clock>)
- return __format::__write(std::move(__out), __utc);
- }
- else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
- {
- if (__t._M_abbrev)
- {
- string_view __sv = *__t._M_abbrev;
- if constexpr (is_same_v<_CharT, char>)
- return __format::__write(std::move(__out), __sv);
- else
- {
- // TODO use resize_and_overwrite
- basic_string<_CharT> __ws(__sv.size(), _CharT());
- auto& __ct = use_facet<ctype<_CharT>>(_M_locale(__ctx));
- __ct.widen(__sv.begin(), __sv.end(), __ws.data());
- __string_view __wsv = __ws;
- return __format::__write(std::move(__out), __wsv);
- }
- }
- }
- else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
- return __format::__write(std::move(__out), __utc);
+ _CharT __buf[6];
+ __buf[0] = _S_plus_minus[__hms.is_negative()];
+ __buf[3] = _S_colon;
+ _S_fill_two_digits(__buf + 1, __hms.hours().count());
+ _S_fill_two_digits(__buf + __mo, __hms.minutes().count());
- __no_timezone_available();
+ __string_view __sv(__buf, __mo + 2);
+ return __format::__write(std::move(__out), __sv);
}
+ template<typename _OutIter>
+ _OutIter
+ _M_Z(__string_view __abbrev, _OutIter __out) const
+ { return __format::__write(std::move(__out), __abbrev); }
+
// %% handled in _M_format
- // A single digit character in the range '0'..'9'.
- static _CharT
+ // A string view of single digit character, "0".."9".
+ static basic_string_view<_CharT>
_S_digit(int __n) noexcept
{
// Extra 9s avoid past-the-end read on bad input.
- return _GLIBCXX_WIDEN("0123456789999999")[__n & 0xf];
+ return { _GLIBCXX_WIDEN("0123456789999999") + (__n & 0xf), 1 };
}
// A string view of two digit characters, "00".."99".
@@ -1553,178 +1737,305 @@ namespace __format
};
}
- // Accessors for the components of chrono types:
+ // Fills __buf[0] and __buf[1] with 2 digit value of __n.
+ [[__gnu__::__always_inline__]]
+ static void
+ _S_fill_two_digits(_CharT* __buf, unsigned __n)
+ {
+ auto __sv = _S_two_digits(__n);
+ __buf[0] = __sv[0];
+ __buf[1] = __sv[1];
+ }
+
+ // Returns decimal representation of __n.
+ // Returned string_view may point to __buf.
+ [[__gnu__::__always_inline__]]
+ static basic_string_view<_CharT>
+ _S_str_d1(span<_CharT, 3> __buf, unsigned __n)
+ {
+ if (__n < 10) [[likely]]
+ return _S_digit(__n);
+ return _S_str_d2(__buf, __n);
+ }
+
+ // Returns decimal representation of __n, padded to 2 digits.
+ // Returned string_view may point to __buf.
+ [[__gnu__::__always_inline__]]
+ static basic_string_view<_CharT>
+ _S_str_d2(span<_CharT, 3> __buf, unsigned __n)
+ {
+ if (__n < 100) [[likely]]
+ return _S_two_digits(__n);
+ return _S_str_d3(__buf, __n);
+ }
+
+ // Returns decimal representation of __n, padded to 3 digits.
+ // Returned string_view points to __buf.
+ [[__gnu__::__always_inline__]]
+ static basic_string_view<_CharT>
+ _S_str_d3(span<_CharT, 3> __buf, unsigned __n)
+ {
+ _S_fill_two_digits(__buf.data(), __n / 10);
+ __buf[2] = _S_chars[__n % 10];
+ return __string_view(__buf.data(), 3);
+ }
+ };
- // Returns a hh_mm_ss.
- template<typename _Tp>
- static decltype(auto)
- _S_hms(const _Tp& __t)
+ template<typename _CharT>
+ struct __formatter_duration : private __formatter_chrono<_CharT>
+ {
+ template<typename _Rep, typename _Period>
+ constexpr static auto
+ _S_subseconds(const chrono::duration<_Rep, _Period>& __d)
{
- using ::std::chrono::__detail::__utc_leap_second;
- using ::std::chrono::__detail::__local_time_fmt;
-
- if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>)
- return __t;
- else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
- return __t._M_time;
- else if constexpr (chrono::__is_duration_v<_Tp>)
- return chrono::hh_mm_ss<_Tp>(__t);
- else if constexpr (chrono::__is_time_point_v<_Tp>)
- return chrono::hh_mm_ss(__t - chrono::floor<chrono::days>(__t));
- else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
- return _S_hms(__t._M_time);
+ if constexpr (chrono::treat_as_floating_point_v<_Rep>)
+ return chrono::duration<_Rep>(__d);
+ else if constexpr (_Period::den == 1)
+ return chrono::seconds(0);
else
- {
- __invalid_chrono_spec();
- return chrono::hh_mm_ss<chrono::seconds>();
- }
- }
+ {
+ using _Attoseconds = _ChronoData<_CharT>::_Attoseconds;
+ using _CRep = common_type_t<_Rep, typename _Attoseconds::rep>;
+ chrono::duration<_CRep, _Period> subs(__d.count());
+ return chrono::duration_cast<_Attoseconds>(subs);
+ }
+ }
- // Returns a sys_days or local_days.
- template<typename _Tp>
- static auto
- _S_days(const _Tp& __t)
+ public:
+ template<typename _Duration>
+ static consteval
+ _ChronoSpec<_CharT>
+ _S_spec_for(_ChronoParts __parts)
{
- using namespace chrono;
- using ::std::chrono::__detail::__utc_leap_second;
- using ::std::chrono::__detail::__local_time_fmt;
-
- if constexpr (__is_time_point_v<_Tp>)
- return chrono::floor<days>(__t);
- else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
- return __t._M_date;
- else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
- return chrono::floor<days>(__t._M_time);
- else if constexpr (is_same_v<_Tp, year_month_day>
- || is_same_v<_Tp, year_month_day_last>
- || is_same_v<_Tp, year_month_weekday>
- || is_same_v<_Tp, year_month_weekday_last>)
- return sys_days(__t);
- else
+ using _Rep = typename _Duration::rep;
+ using enum _ChronoParts;
+
+ _ChronoSpec<_CharT> __res{};
+ __res._M_time_only = (__parts & _Date) == 0;
+ __res._M_floating_point_rep = chrono::treat_as_floating_point_v<_Rep>;
+ __res._M_custom_rep = !is_arithmetic_v<_Rep>;
+ __res._M_prec = chrono::hh_mm_ss<_Duration>::fractional_width;
+ if ((__parts & _TimeOfDay) != 0)
+ __res._M_localized = __res._M_prec > 0 || __res._M_floating_point_rep;
+
+ if ((__parts & _TimeOfDay) != 0)
+ __res._M_needed |= _TimeOfDay;
+ if ((__parts & _Date) != 0)
+ __res._M_needed |= _YearMonthDay;
+ if ((__parts & _ZoneAbbrev) != 0)
+ __res._M_needed |= _ZoneAbbrev;
+
+ switch (__parts)
{
- if constexpr (__is_duration_v<_Tp>)
- __not_valid_for_duration();
- else
- __invalid_chrono_spec();
- return chrono::sys_days();
+ case _ZonedDateTime:
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ftz();
+ break;
+ case _DateTime:
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ft();
+ break;
+ case _Date:
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_f();
+ break;
+ case _Time:
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_t();
+ break;
+ case _None:
+ break;
}
- }
+ return __res;
+ };
- // Returns a year_month_day.
- template<typename _Tp>
- static chrono::year_month_day
- _S_date(const _Tp& __t)
+ using __formatter_chrono<_CharT>::__formatter_chrono;
+ using __formatter_chrono<_CharT>::_M_locale;
+ using __formatter_chrono<_CharT>::_M_spec;
+
+ template<typename _Duration, typename _ParseContext>
+ constexpr typename _ParseContext::iterator
+ _M_parse(_ParseContext& __pc, _ChronoParts __parts,
+ const _ChronoSpec<_CharT>& __def = {})
{
- if constexpr (is_same_v<_Tp, chrono::year_month_day>)
- return __t;
- else
- return chrono::year_month_day(_S_days(__t));
+ using _Rep = typename _Duration::rep;
+ using enum _ChronoParts;
+
+ auto __res
+ = __formatter_chrono<_CharT>::_M_parse(__pc, __parts, __def);
+ // check for custom floating point durations, if digits of output
+ // will contain subseconds, then formatters must support specifying
+ // precision.
+ if constexpr (!is_floating_point_v<_Rep>)
+ if constexpr (chrono::treat_as_floating_point_v<_Rep>)
+ if (_M_spec._M_needs(_Subseconds|_EpochUnits)
+ || _M_spec._M_prec_kind != _WP_none
+ || _M_spec._M_prec_value > 0)
+ {
+ constexpr const _CharT* __fs = _GLIBCXX_WIDEN("#02.5Lf");
+ basic_format_parse_context<_CharT> __npc(__fs);
+ formatter<_Rep, _CharT> __fmtter;
+ __fmtter.parse(__npc);
+ }
+ return __res;
}
- template<typename _Tp>
- static chrono::day
- _S_day(const _Tp& __t)
+ // Format duration for empty chrono-specs, e.g. "{}" (C++20 [time.format] p6).
+ template<typename _Rep, typename _Period, typename _FormatContext>
+ typename _FormatContext::iterator
+ _M_format_to_ostream(const chrono::duration<_Rep, _Period>& __d,
+ bool __is_neg,
+ _FormatContext& __fc) const
{
- using namespace chrono;
+ basic_ostringstream<_CharT> __os;
+ __os.imbue(this->_M_locale(__fc));
- if constexpr (is_same_v<_Tp, day>)
- return __t;
- else if constexpr (requires { __t.day(); })
- return __t.day();
- else
- return _S_date(__t).day();
+ if (__is_neg) [[unlikely]]
+ __os << this->_S_plus_minus[1];
+ __os << __d;
+
+ auto __str = std::move(__os).str();
+ return __format::__write_padded_as_spec(__str, __str.size(),
+ __fc, _M_spec);
}
- template<typename _Tp>
- static chrono::month
- _S_month(const _Tp& __t)
+ template<typename _Rep1, typename _Period1,
+ typename _Rep2, typename _Period2,
+ typename _FormatContext>
+ typename _FormatContext::iterator
+ _M_format_units(_ChronoData<_CharT>& __cd,
+ const chrono::duration<_Rep1, _Period1>& __ed,
+ const chrono::duration<_Rep2, _Period2>& __ss,
+ _FormatContext& __fc) const
{
- using namespace chrono;
+ __format::_Str_sink<_CharT> __suffix_store;
+ constexpr auto _S_unit_suffix
+ = chrono::__detail::__units_suffix<_Period1, _CharT>();
+ if constexpr (!_S_unit_suffix.empty())
+ __cd._M_unit_suffix = _S_unit_suffix;
+ else if (_M_spec._M_needs(_ChronoParts::_UnitSuffix))
+ {
+ chrono::__detail::
+ __fmt_units_suffix<_Period1, _CharT>(__suffix_store.out());
+ __cd._M_unit_suffix = __suffix_store.view();
+ }
- if constexpr (is_same_v<_Tp, month>)
- return __t;
- else if constexpr (requires { __t.month(); })
- return __t.month();
- else
- return _S_date(__t).month();
- }
+ const auto __prec = _M_spec._M_prec_kind != _WP_none
+ ? _M_spec._M_get_precision(__fc)
+ : _M_spec._M_prec;
- template<typename _Tp>
- static chrono::year
- _S_year(const _Tp& __t)
- {
- using namespace chrono;
+ using _ErasedContext = typename _ChronoData<_CharT>::_FormatContext;
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4118. How should duration formatters format custom rep?
+ auto __ereps = +__ed.count();
+ if (!_M_spec._M_needs(_ChronoParts::_Subseconds))
+ {
+ auto __ssreps = 0u;
+ auto __args_store
+ = std::make_format_args<_ErasedContext>(__ereps, __ssreps, __prec);
+ __cd._M_ereps = __args_store;
+ return this->_M_format(__cd, __fc);
+ }
- if constexpr (is_same_v<_Tp, year>)
- return __t;
- else if constexpr (requires { __t.year(); })
- return __t.year();
- else
- return _S_date(__t).year();
+ using _Attoseconds = _ChronoData<_CharT>::_Attoseconds;
+ auto __nss = _S_subseconds(__ss);
+ __cd._M_subseconds = chrono::duration_cast<_Attoseconds>(__nss);
+
+ auto __ssreps = __nss.count();
+ auto __args_store
+ = std::make_format_args<_ErasedContext>(__ereps, __ssreps, __prec);
+ __cd._M_ereps = __args_store;
+
+ return this->_M_format(__cd, __fc);
}
- template<typename _Tp>
- static chrono::weekday
- _S_weekday(const _Tp& __t)
+ // pre: __cd._M_lseconds and __cd._M_eseconds are set.
+ template<typename _Rep1, typename _Period1, typename _FormatContext>
+ typename _FormatContext::iterator
+ _M_format_time_point(_ChronoData<_CharT>& __cd,
+ const chrono::duration<_Rep1, _Period1>& __ed,
+ _FormatContext& __fc) const
{
- using namespace ::std::chrono;
- using ::std::chrono::__detail::__local_time_fmt;
-
- if constexpr (is_same_v<_Tp, weekday>)
- return __t;
- else if constexpr (requires { __t.weekday(); })
- return __t.weekday();
- else if constexpr (is_same_v<_Tp, month_weekday>)
- return __t.weekday_indexed().weekday();
- else if constexpr (is_same_v<_Tp, month_weekday_last>)
- return __t.weekday_last().weekday();
- else
- return weekday(_S_days(__t));
+ auto __parts = _M_spec._M_needed - _ChronoParts::_TotalSeconds;
+ if ((__parts & _ChronoParts::_DateTime) != 0)
+ __cd._M_fill_date_time(__cd._M_lseconds, __parts);
+ return _M_format_units(__cd, __ed, __ed - __cd._M_eseconds, __fc);
}
+ };
+
+#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
+ template<typename _CharT>
+ struct __formatter_chrono_info
+ {
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ { return _M_f._M_parse(__pc, _ChronoParts(), {}); }
- // Remove subsecond precision from a time_point.
- template<typename _Tp>
- static auto
- _S_floor_seconds(const _Tp& __t)
+ template<typename _Info, typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(const _Info& __i,
+ basic_format_context<_Out, _CharT>& __fc) const
{
- using chrono::__detail::__local_time_fmt;
- if constexpr (chrono::__is_time_point_v<_Tp>
- || chrono::__is_duration_v<_Tp>)
- {
- if constexpr (_Tp::period::den != 1)
- return chrono::floor<chrono::seconds>(__t);
- else
- return __t;
- }
- else if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>)
+ // n.b. only acceptable chrono-spec for info is one containing
+ // only whitespaces and %%, that do not depend on formatted object.
+ if (!_M_f._M_spec._M_chrono_specs.empty()) [[unlikely]]
+ return _M_f._M_format(_ChronoData<_CharT>{}, __fc);
+
+ const size_t __padwidth = _M_f._M_spec._M_get_width(__fc);
+ if (__padwidth == 0)
+ return _M_format_to(__fc.out(), __i);
+
+ _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth);
+ _M_format_to(__sink.out(), __i);
+ return __sink._M_finish(_M_f._M_spec._M_align, _M_f._M_spec._M_fill);
+ }
+
+ private:
+ template<typename _Out>
+ _Out
+ _M_format_to(_Out __out, const chrono::sys_info& __si) const
+ {
+ using _FmtStr = _Runtime_format_string<_CharT>;
+ // n.b. only decimal separator is locale dependent for specifiers
+ // used below, as sys_info uses seconds and minutes duration, the
+ // output is locale-independent.
+ constexpr auto* __fs
+ = _GLIBCXX_WIDEN("[{0:%F %T},{1:%F %T},{2:%T},{3:%Q%q},{0:%Z}]");
+ const chrono::local_seconds __lb(__si.begin.time_since_epoch());
+ return std::format_to(std::move(__out), _FmtStr(__fs),
+ chrono::local_time_format(__lb, &__si.abbrev),
+ __si.end, __si.offset, __si.save);
+ }
+
+ template<typename _Out>
+ _Out
+ _M_format_to(_Out __out, const chrono::local_info& __li) const
+ {
+ *__out = _Separators<_CharT>::_S_squares()[0];
+ ++__out;
+ if (__li.result == chrono::local_info::unique)
+ __out = _M_format_to(std::move(__out), __li.first);
+ else
{
- if constexpr (_Tp::fractional_width != 0)
- return chrono::floor<chrono::seconds>(__t.to_duration());
+ basic_string_view<_CharT> __sv;
+ if (__li.result == chrono::local_info::nonexistent)
+ __sv =_GLIBCXX_WIDEN("nonexistent");
else
- return __t;
+ __sv = _GLIBCXX_WIDEN("ambiguous");
+ __out = __format::__write(std::move(__out), __sv);
+
+ __sv = _GLIBCXX_WIDEN(" local time between ");
+ __out = __format::__write(std::move(__out), __sv);
+ __out = _M_format_to(std::move(__out), __li.first);
+
+ __sv = _GLIBCXX_WIDEN(" and ");
+ __out = __format::__write(std::move(__out), __sv);
+ __out = _M_format_to(std::move(__out), __li.second);
}
- else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
- return _S_floor_seconds(__t._M_time);
- else
- return __t;
+ *__out = _Separators<_CharT>::_S_squares()[1];
+ ++__out;
+ return std::move(__out);
}
- // Use the formatting locale's std::time_put facet to produce
- // a locale-specific representation.
- template<typename _Iter>
- _Iter
- _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm& __tm,
- char __fmt, char __mod) const
- {
- basic_ostringstream<_CharT> __os;
- __os.imbue(__loc);
- const auto& __tp = use_facet<time_put<_CharT>>(__loc);
- __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
- if (__os)
- __out = _M_write(std::move(__out), __loc, __os.view());
- return __out;
- }
+ __formatter_chrono<_CharT> _M_f;
};
+#endif
} // namespace __format
/// @endcond
@@ -1736,12 +2047,8 @@ namespace __format
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
{
- using namespace __format;
- auto __it = _M_f._M_parse(__pc, _Duration|_TimeOfDay);
- if constexpr (!is_floating_point_v<_Rep>)
- if (_M_f._M_spec._M_prec_kind != __format::_WP_none)
- __throw_format_error("format error: invalid precision for duration");
- return __it;
+ using enum __format::_ChronoParts;
+ return _M_f.template _M_parse<_Duration>(__pc, _EpochTime, __defSpec);
}
template<typename _Out>
@@ -1759,16 +2066,54 @@ namespace __format
using _URep = make_unsigned_t<_Rep>;
auto __ucnt = -static_cast<_URep>(__d.count());
auto __ud = chrono::duration<_URep, _Period>(__ucnt);
- return _M_f._M_format(__ud, __fc, true);
+ return _M_format(__ud, true, __fc);
}
else
- return _M_f._M_format(-__d, __fc, true);
+ return _M_format(-__d, true, __fc);
}
- return _M_f._M_format(__d, __fc, false);
+ return _M_format(__d, false, __fc);
}
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ using _Duration = chrono::duration<_Rep, _Period>;
+
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using enum __format::_ChronoParts;
+ auto __res = __format::__formatter_duration<_CharT>::
+ template _S_spec_for<_Duration>(_None);
+ __res._M_localized = !is_integral_v<_Rep>;
+ // n.b. for integral format output is the same as ostream output
+ if constexpr (is_integral_v<_Rep>)
+ {
+ __res._M_needed = _EpochUnits|_UnitSuffix;
+ __res._M_chrono_specs = _GLIBCXX_WIDEN("%Q%q");
+ }
+ return __res;
+ }();
+
+ template<typename _Rep2, typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ _M_format(const chrono::duration<_Rep2, _Period>& __d,
+ bool __is_neg,
+ basic_format_context<_Out, _CharT>& __fc) const
+ {
+ using namespace chrono;
+ using enum __format::_ChronoParts;
+ if constexpr (!is_integral_v<_Rep>)
+ if (_M_f._M_spec._M_chrono_specs.empty())
+ return _M_f._M_format_to_ostream(__d, __is_neg, __fc);
+
+ __format::_ChronoData<_CharT> __cd;
+ __cd._M_is_neg = __is_neg;
+ auto __ts = chrono::floor<chrono::seconds>(__d);
+ __cd._M_eseconds = __ts;
+ if (_M_f._M_spec._M_needs(_HoursMinutesSeconds))
+ __cd._M_fill_time(__ts);
+ return _M_f._M_format_units(__cd, __d, __d - __ts, __fc);
+ }
+
+ __format::__formatter_duration<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1776,16 +2121,35 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Day); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Day|_WeekdayIndex, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::day& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_fill_day(__t, __defSpec._M_needed);
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_needed = _Day;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_d();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1793,16 +2157,37 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Month); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Month, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::month& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_month = __t;
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Month;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_m();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1810,16 +2195,35 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Year); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Year, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::year& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_year = __t;
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_needed = _Year;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_y();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1827,16 +2231,37 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Weekday); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Weekday, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::weekday& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_weekday = __t;
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Weekday;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_w();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1844,16 +2269,37 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Weekday); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _IndexedWeekday, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::weekday_indexed& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_fill_weekday(__t, __defSpec._M_needed);
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _IndexedWeekday;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_wi();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1861,16 +2307,37 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Weekday); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Weekday, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::weekday_last& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_weekday = __t.weekday();
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Weekday;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_wl();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1878,16 +2345,38 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Month|_Day|_WeekdayIndex, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::month_day& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_month = __t.month();
+ __cd._M_fill_day(__t.day(), __defSpec._M_needed);
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Month|_Day;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_md();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1895,16 +2384,37 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Month, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::month_day_last& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_month = __t.month();
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Month;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ml();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1912,16 +2422,38 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Month|_IndexedWeekday, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::month_weekday& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_month = __t.month();
+ __cd._M_fill_weekday(__t.weekday_indexed(), __defSpec._M_needed);
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Month|_IndexedWeekday;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_mwi();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1929,16 +2461,38 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Month|_Weekday, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::month_weekday_last& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_month = __t.month();
+ __cd._M_weekday = __t.weekday_last().weekday();
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Month|_Weekday;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_mwl();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1946,16 +2500,37 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Year|__format::_Month); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Year|_Month, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::year_month& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_fill_year_month(__t, __defSpec._M_needed);
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Year|_Month;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ym();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1963,16 +2538,42 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Date); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Date, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::year_month_day& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ auto __parts = _M_f._M_spec._M_needed;
+ __parts = __cd._M_fill_year_month(__t, __parts);
+ __parts = __cd._M_fill_day(__t.day(), __parts);
+ if (__parts == 0)
+ return _M_f._M_format(__cd, __fc);
+
+ chrono::local_days __ld(__t);
+ __cd._M_fill_ldays(__ld, __parts);
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_needed = _YearMonthDay;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_f();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1980,16 +2581,48 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Date); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Date, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::year_month_day_last& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ auto __parts = _M_f._M_spec._M_needed;
+ __parts = __cd._M_fill_year_month(__t, __parts);
+ if (__parts == 0)
+ return _M_f._M_format(__cd, __fc);
+
+ chrono::local_days __ld(__t);
+ __parts = __cd._M_fill_ldays(__ld, __parts);
+ if (__parts == 0)
+ return _M_f._M_format(__cd, __fc);
+
+ chrono::year_month_day __ymd(__ld);
+ __cd._M_fill_day(__ymd.day(), __parts);
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Year|_Month;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_yml();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -1997,16 +2630,50 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Date); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Date, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::year_month_weekday& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ auto __parts = _M_f._M_spec._M_needed;
+ __parts = __cd._M_fill_year_month(__t, __parts);
+ __parts = __cd._M_fill_weekday(__t.weekday_indexed(), __parts);
+ if (__parts == 0)
+ return _M_f._M_format(__cd, __fc);
+
+ chrono::local_days __ld(__t);
+ __parts = __cd._M_fill_ldays(__ld, __parts);
+ if (__parts == 0)
+ return _M_f._M_format(__cd, __fc);
+
+ chrono::year_month_day __ymd(__ld);
+ // n.b. weekday index is supplied by input, do not override it
+ __cd._M_day = __ymd.day();
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Year|_Month|_IndexedWeekday;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ymwi();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<__format::__char _CharT>
@@ -2014,16 +2681,50 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_Date); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f._M_parse(__pc, _Date, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::year_month_weekday_last& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ auto __parts = _M_f._M_spec._M_needed;
+ __parts = __cd._M_fill_year_month(__t, __parts);
+ __cd._M_weekday = __t.weekday_last().weekday();
+ __parts -= __format::_ChronoParts::_Weekday;
+ if (__parts == 0)
+ return _M_f._M_format(__cd, __fc);
+
+ chrono::local_days __ld(__t);
+ __parts = __cd._M_fill_ldays(__ld, __parts);
+ if (__parts == 0)
+ return _M_f._M_format(__cd, __fc);
+
+ chrono::year_month_day __ymd(__ld);
+ __cd._M_fill_day(__ymd.day(), __parts);
+ return _M_f._M_format(__cd, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using __format::_ChronoFormats;
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoSpec<_CharT> __res{};
+ __res._M_debug = true;
+ __res._M_localized = true;
+ __res._M_locale_specific = true;
+ __res._M_needed = _Year|_Month|_Weekday;
+ __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ymwl();
+ return __res;
+ }();
+
+ __format::__formatter_chrono<_CharT> _M_f{__defSpec};
};
template<typename _Rep, typename _Period, __format::__char _CharT>
@@ -2031,16 +2732,43 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_TimeOfDay); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f.template _M_parse<_Precision>(__pc, _Time, __defSpec);
+ }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ using enum __format::_ChronoParts;
+
+ __format::_ChronoData<_CharT> __cd;
+ __cd._M_is_neg = __t.is_negative();
+ __cd._M_hours = __t.hours();
+ __cd._M_minutes = __t.minutes();
+ __cd._M_seconds = __t.seconds();
+
+ _Precision __d(0);
+ // n.b. computing total duration or total seconds may overflow,
+ // do not compute them if not requested.
+ if (_M_f._M_spec._M_needs(_EpochUnits))
+ __d = __t.to_duration();
+ if (_M_f._M_spec._M_needs(_TotalSeconds))
+ __cd._M_eseconds
+ = __cd._M_hours + __cd._M_minutes + __cd._M_seconds;
+ return _M_f._M_format_units(__cd, __d, __t.subseconds(), __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ using _Precision
+ = typename chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>::precision;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec =
+ __format::__formatter_duration<_CharT>::
+ template _S_spec_for<_Precision>(__format::_ChronoParts::_Time);
+
+ __format::__formatter_duration<_CharT> _M_f{__defSpec};
};
#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
@@ -2049,16 +2777,16 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_ChronoParts{}); }
+ { return _M_f.parse(__pc); }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::sys_info& __i,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__i, __fc); }
+ { return _M_f.format(__i, __fc); }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ __format::__formatter_chrono_info<_CharT> _M_f;
};
template<__format::__char _CharT>
@@ -2066,16 +2794,16 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_ChronoParts{}); }
+ { return _M_f.parse(__pc); }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::local_info& __i,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__i, __fc); }
+ { return _M_f.format(__i, __fc); }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ __format::__formatter_chrono_info<_CharT> _M_f;
};
#endif
@@ -2085,7 +2813,9 @@ namespace __format
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
{
- auto __next = _M_f._M_parse(__pc, __format::_ZonedDateTime);
+ using enum __format::_ChronoParts;
+ auto __next
+ = _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
if constexpr (!__stream_insertable)
if (_M_f._M_spec._M_chrono_specs.empty())
__format::__invalid_chrono_spec(); // chrono-specs can't be empty
@@ -2096,14 +2826,34 @@ namespace __format
typename basic_format_context<_Out, _CharT>::iterator
format(const chrono::sys_time<_Duration>& __t,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_fill_utc_zone();
+
+ _Duration __ed = __t.time_since_epoch();
+ __cd._M_eseconds = chrono::floor<chrono::seconds>(__ed);
+ __cd._M_lseconds = chrono::local_seconds(__cd._M_eseconds);
+ return _M_f._M_format_time_point(__cd, __ed, __fc);
+ }
private:
static constexpr bool __stream_insertable
= requires (basic_ostream<_CharT>& __os,
chrono::sys_time<_Duration> __t) { __os << __t; };
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using enum __format::_ChronoParts;
+ __format::_ChronoParts __needed = _DateTime;
+ if constexpr (!__stream_insertable)
+ __needed = _None;
+ else if constexpr (is_convertible_v<_Duration, chrono::days>)
+ __needed = _Date;
+ return __format::__formatter_duration<_CharT>::
+ template _S_spec_for<_Duration>(__needed);
+ }();
+
+ __format::__formatter_duration<_CharT> _M_f{__defSpec};
};
template<typename _Duration, __format::__char _CharT>
@@ -2112,32 +2862,43 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
+ }
template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(const chrono::utc_time<_Duration>& __t,
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(const chrono::utc_time<_Duration>& __t,
basic_format_context<_Out, _CharT>& __fc) const
{
+ using __format::_ChronoParts;
+ using namespace chrono;
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_fill_utc_zone();
+
+ _Duration __ed = __t.time_since_epoch();
+ __cd._M_eseconds = chrono::floor<seconds>(__ed);
// Adjust by removing leap seconds to get equivalent sys_time.
// We can't just use clock_cast because we want to know if the time
// falls within a leap second insertion, and format seconds as "60".
- using chrono::__detail::__utc_leap_second;
- using chrono::seconds;
- using chrono::sys_time;
- using _CDur = common_type_t<_Duration, seconds>;
const auto __li = chrono::get_leap_second_info(__t);
- sys_time<_CDur> __s{__t.time_since_epoch() - __li.elapsed};
- if (!__li.is_leap_second) [[likely]]
- return _M_f._M_format(__s, __fc);
- else
- return _M_f._M_format(__utc_leap_second(__s), __fc);
+ __cd._M_lseconds = local_seconds(__cd._M_eseconds - __li.elapsed);
+ auto __parts = _M_f._M_spec._M_needed - _ChronoParts::_TotalSeconds;
+ if ((__parts & _ChronoParts::_DateTime) != 0)
+ {
+ __cd._M_fill_date_time(__cd._M_lseconds, __parts);
+ __cd._M_seconds += seconds(__li.is_leap_second);
+ }
+ return _M_f._M_format_units(__cd, __ed, __ed - __cd._M_eseconds, __fc);
}
private:
- friend formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT>;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec =
+ __format::__formatter_duration<_CharT>::
+ template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
- __format::__formatter_chrono<_CharT> _M_f;
+ __format::__formatter_duration<_CharT> _M_f{__defSpec};
};
template<typename _Duration, __format::__char _CharT>
@@ -2146,29 +2907,34 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
+ }
template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(const chrono::tai_time<_Duration>& __t,
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(const chrono::tai_time<_Duration>& __t,
basic_format_context<_Out, _CharT>& __fc) const
{
- // Convert to __local_time_fmt with abbrev "TAI" and offset 0s.
- // We use __local_time_fmt and not sys_time (as the standard implies)
- // because %Z for sys_time would print "UTC" and we want "TAI" here.
+ using namespace chrono;
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_fill_zone("TAI", L"TAI");
+ _Duration __ed = __t.time_since_epoch();
+ __cd._M_eseconds = chrono::floor<seconds>(__ed);
// Offset is 1970y/January/1 - 1958y/January/1
constexpr chrono::days __tai_offset = chrono::days(4383);
- using _CDur = common_type_t<_Duration, chrono::days>;
- chrono::local_time<_CDur> __lt(__t.time_since_epoch() - __tai_offset);
- const string __abbrev("TAI", 3);
- const chrono::seconds __off = 0s;
- const auto __lf = chrono::local_time_format(__lt, &__abbrev, &__off);
- return _M_f._M_format(__lf, __fc);
+ __cd._M_lseconds = local_seconds(__cd._M_eseconds - __tai_offset);
+ return _M_f._M_format_time_point(__cd, __ed, __fc);
}
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec =
+ __format::__formatter_duration<_CharT>::
+ template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
+
+ __format::__formatter_duration<_CharT> _M_f{__defSpec};
};
template<typename _Duration, __format::__char _CharT>
@@ -2177,29 +2943,34 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
+ }
template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(const chrono::gps_time<_Duration>& __t,
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(const chrono::gps_time<_Duration>& __t,
basic_format_context<_Out, _CharT>& __fc) const
{
- // Convert to __local_time_fmt with abbrev "GPS" and offset 0s.
- // We use __local_time_fmt and not sys_time (as the standard implies)
- // because %Z for sys_time would print "UTC" and we want "GPS" here.
+ using namespace chrono;
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_fill_zone("GPS", L"GPS");
+ _Duration __ed = __t.time_since_epoch();
+ __cd._M_eseconds = chrono::floor<seconds>(__ed);
// Offset is 1980y/January/Sunday[1] - 1970y/January/1
constexpr chrono::days __gps_offset = chrono::days(3657);
- using _CDur = common_type_t<_Duration, chrono::days>;
- chrono::local_time<_CDur> __lt(__t.time_since_epoch() + __gps_offset);
- const string __abbrev("GPS", 3);
- const chrono::seconds __off = 0s;
- const auto __lf = chrono::local_time_format(__lt, &__abbrev, &__off);
- return _M_f._M_format(__lf, __fc);
+ __cd._M_lseconds = local_seconds(__cd._M_eseconds + __gps_offset);
+ return _M_f._M_format_time_point(__cd, __ed, __fc);
}
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec =
+ __format::__formatter_duration<_CharT>::
+ template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
+
+ __format::__formatter_duration<_CharT> _M_f{__defSpec};
};
template<typename _Duration, __format::__char _CharT>
@@ -2207,36 +2978,70 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
+ }
template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(const chrono::file_time<_Duration>& __t,
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(const chrono::file_time<_Duration>& __t,
basic_format_context<_Out, _CharT>& __fc) const
{
using namespace chrono;
- return _M_f._M_format(chrono::clock_cast<system_clock>(__t), __fc);
+ __format::_ChronoData<_CharT> __cd{};
+ __cd._M_fill_utc_zone();
+
+ _Duration __ed = __t.time_since_epoch();
+ __cd._M_eseconds = chrono::floor<seconds>(__ed);
+ auto __st = chrono::clock_cast<system_clock>(__t);
+ __cd._M_lseconds
+ = local_seconds(chrono::floor<seconds>(__st.time_since_epoch()));
+ return _M_f._M_format_time_point(__cd, __ed, __fc);
}
private:
- __format::__formatter_chrono<_CharT> _M_f;
- };
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec =
+ __format::__formatter_duration<_CharT>::
+ template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
+
+ __format::__formatter_duration<_CharT> _M_f{__defSpec};
+ };
template<typename _Duration, __format::__char _CharT>
struct formatter<chrono::local_time<_Duration>, _CharT>
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_DateTime); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f.template _M_parse<_Duration>(__pc, _DateTime, __defSpec);
+ }
template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(const chrono::local_time<_Duration>& __t,
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(const chrono::local_time<_Duration>& __lt,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc); }
+ {
+ __format::_ChronoData<_CharT> __cd{};
+ _Duration __ed = __lt.time_since_epoch();
+ __cd._M_lseconds = chrono::floor<chrono::seconds>(__lt);
+ __cd._M_eseconds = __cd._M_lseconds.time_since_epoch();
+ return _M_f._M_format_time_point(__cd, __ed, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+ {
+ using enum __format::_ChronoParts;
+ __format::_ChronoParts __needed = _DateTime;
+ if constexpr (is_convertible_v<_Duration, chrono::days>)
+ __needed = _Date;
+ return __format::__formatter_duration<_CharT>::
+ template _S_spec_for<_Duration>(__needed);
+ }();
+
+ __format::__formatter_duration<_CharT> _M_f{__defSpec};
};
template<typename _Duration, __format::__char _CharT>
@@ -2244,16 +3049,59 @@ namespace __format
{
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
+ {
+ using enum __format::_ChronoParts;
+ return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
+ }
template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(const chrono::__detail::__local_time_fmt<_Duration>& __t,
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(const chrono::__detail::__local_time_fmt<_Duration>& __zt,
basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f._M_format(__t, __fc, /* use %Z for {} */ true); }
+ {
+ using enum __format::_ChronoParts;
+ __format::_ChronoData<_CharT> __cd{};
+
+ if (_M_f._M_spec._M_needs(_ZoneOffset))
+ {
+ if (!__zt._M_offset_sec)
+ std::__throw_format_error("format error: no timezone available for %z");
+ __cd._M_zone_offset = *__zt._M_offset_sec;
+ }
+
+ basic_string<_CharT> __zone_store;
+ if (_M_f._M_spec._M_needs(_ZoneAbbrev))
+ {
+ if (!__zt._M_abbrev)
+ std::__throw_format_error("format error: no timezone available for %Z");
+
+ __cd._M_zone_cstr = __zt._M_abbrev->data();
+ if constexpr (is_same_v<_CharT, char>)
+ __cd._M_zone_abbrev = *__zt._M_abbrev;
+ else
+ {
+ // TODO: use resize_for_override
+ __zone_store.resize(__zt._M_abbrev->size());
+ auto& __ct = use_facet<ctype<_CharT>>(_M_f._M_locale(__fc));
+ __ct.widen(__zt._M_abbrev->data(),
+ __zt._M_abbrev->data() + __zt._M_abbrev->size(),
+ __zone_store.data());
+ __cd._M_zone_abbrev = __zone_store;
+ }
+ }
+
+ _Duration __ed = __zt._M_time.time_since_epoch();
+ __cd._M_lseconds = chrono::floor<chrono::seconds>(__zt._M_time);
+ __cd._M_eseconds = __cd._M_lseconds.time_since_epoch();
+ return _M_f._M_format_time_point(__cd, __ed, __fc);
+ }
private:
- __format::__formatter_chrono<_CharT> _M_f;
+ static constexpr __format::_ChronoSpec<_CharT> __defSpec =
+ __format::__formatter_duration<_CharT>::
+ template _S_spec_for<_Duration>(__format::_ChronoParts::_ZonedDateTime);
+
+ __format::__formatter_duration<_CharT> _M_f{__defSpec};
};
#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
@@ -2262,8 +3110,8 @@ namespace __format
: formatter<chrono::__detail::__local_time_fmt_for<_Duration>, _CharT>
{
template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp,
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp,
basic_format_context<_Out, _CharT>& __fc) const
{
using _Ltf = chrono::__detail::__local_time_fmt_for<_Duration>;
@@ -2277,18 +3125,6 @@ namespace __format
};
#endif
- // Partial specialization needed for %c formatting of __utc_leap_second.
- template<typename _Duration, __format::__char _CharT>
- struct formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT>
- : formatter<chrono::utc_time<_Duration>, _CharT>
- {
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(const chrono::__detail::__utc_leap_second<_Duration>& __t,
- basic_format_context<_Out, _CharT>& __fc) const
- { return this->_M_f._M_format(__t, __fc); }
- };
-
namespace chrono
{
/// @addtogroup chrono
@@ -2869,10 +3705,7 @@ namespace __detail
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __i)
{
- __os << '[' << __i.begin << ',' << __i.end
- << ',' << hh_mm_ss(__i.offset) << ',' << __i.save
- << ',' << __i.abbrev << ']';
- return __os;
+ return __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{}"), __i);
}
/// Writes a local_info object to an ostream in an unspecified format.
@@ -2880,19 +3713,19 @@ namespace __detail
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __li)
{
- __os << '[';
+ __os << __format::_Separators<_CharT>::_S_squares()[0];
if (__li.result == local_info::unique)
__os << __li.first;
else
{
if (__li.result == local_info::nonexistent)
- __os << "nonexistent";
+ __os << _GLIBCXX_WIDEN("nonexistent");
else
- __os << "ambiguous";
- __os << " local time between " << __li.first;
- __os << " and " << __li.second;
+ __os << _GLIBCXX_WIDEN("ambiguous");
+ __os << _GLIBCXX_WIDEN(" local time between ") << __li.first;
+ __os << _GLIBCXX_WIDEN(" and ") << __li.second;
}
- __os << ']';
+ __os << __format::_Separators<_CharT>::_S_squares()[1];
return __os;
}
@@ -3049,8 +3882,7 @@ namespace __detail
if (!__offset)
__offset = &__off;
using __format::_ChronoParts;
- auto __need = _ChronoParts::_Year | _ChronoParts::_Month
- | _ChronoParts::_Day | _ChronoParts::_TimeOfDay;
+ auto __need = _ChronoParts::_YearMonthDay | _ChronoParts::_TimeOfDay;
__detail::_Parser_t<_Duration> __p(__need);
if (__p(__is, __fmt, __abbrev, __offset))
{
@@ -3108,8 +3940,7 @@ namespace __detail
minutes* __offset = nullptr)
{
using __format::_ChronoParts;
- auto __need = _ChronoParts::_Year | _ChronoParts::_Month
- | _ChronoParts::_Day | _ChronoParts::_TimeOfDay;
+ auto __need = _ChronoParts::_YearMonthDay | _ChronoParts::_TimeOfDay;
__detail::_Parser_t<_Duration> __p(__need);
if (__p(__is, __fmt, __abbrev, __offset))
{
@@ -3362,8 +4193,8 @@ namespace __detail
minutes __tz_offset = __bad_min;
basic_string<_CharT, _Traits> __tz_abbr;
- if ((_M_need & _ChronoParts::_TimeOfDay)
- && (_M_need & _ChronoParts::_Year))
+ if ((_M_need & _ChronoParts::_TimeOfDay) != 0
+ && (_M_need & _ChronoParts::_Year) != 0)
{
// For time_points assume "00:00:00" is implicitly present,
// so we don't fail to parse if it's not (PR libstdc++/114240).
@@ -3636,7 +4467,7 @@ namespace __detail
}
else
{
- if (_M_need & _ChronoParts::_TimeOfDay)
+ if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
__err |= ios_base::failbit;
break;
}
@@ -3704,7 +4535,7 @@ namespace __detail
__min = minutes(__val);
else
{
- if (_M_need & _ChronoParts::_TimeOfDay)
+ if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
__err |= ios_base::failbit;
break;
}
@@ -3794,7 +4625,7 @@ namespace __detail
auto __val = __read_unsigned(2);
if (__val == -1 || __val > 23) [[unlikely]]
{
- if (_M_need & _ChronoParts::_TimeOfDay)
+ if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
__err |= ios_base::failbit;
break;
}
@@ -3805,7 +4636,7 @@ namespace __detail
__val = __read_unsigned(2);
if (__val == -1 || __val > 60) [[unlikely]]
{
- if (_M_need & _ChronoParts::_TimeOfDay)
+ if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
__err |= ios_base::failbit;
break;
}
@@ -3840,7 +4671,7 @@ namespace __detail
__s = seconds(__val);
else
{
- if (_M_need & _ChronoParts::_TimeOfDay)
+ if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
__err |= ios_base::failbit;
break;
}
@@ -4314,23 +5145,23 @@ namespace __detail
// Whether the caller wants _M_wd.
// The _Weekday bit is only set for chrono::weekday.
- const bool __need_wday = _M_need & _ChronoParts::_Weekday;
+ const bool __need_wday = (_M_need & _ChronoParts::_Weekday) != 0;
// Whether the caller wants _M_sys_days and _M_time.
// Only true for durations and time_points.
- const bool __need_time = _M_need & _ChronoParts::_TimeOfDay;
+ const bool __need_time = (_M_need & _ChronoParts::_TimeOfDay) != 0;
if (__need_wday && __wday != __bad_wday)
_M_wd = __wday; // Caller only wants a weekday and we have one.
- else if (_M_need & _ChronoParts::_Date) // subsumes __need_wday
+ else if ((_M_need & _ChronoParts::_Date) != 0) // subsumes __need_wday
{
// Whether the caller wants _M_ymd.
// True for chrono::year etc., false for time_points.
const bool __need_ymd = !__need_wday && !__need_time;
- if ((_M_need & _ChronoParts::_Year && __y == __bad_y)
- || (_M_need & _ChronoParts::_Month && __m == __bad_mon)
- || (_M_need & _ChronoParts::_Day && __d == __bad_day))
+ if (((_M_need & _ChronoParts::_Year) != 0 && __y == __bad_y)
+ || ((_M_need & _ChronoParts::_Month) != 0 && __m == __bad_mon)
+ || ((_M_need & _ChronoParts::_Day) != 0 && __d == __bad_day))
{
// Missing at least one of y/m/d so calculate sys_days
// from the other data we have available.
@@ -4407,7 +5238,7 @@ namespace __detail
// but check that their values are in range.
// Make unwanted fields valid so that _M_ymd.ok() is true.
- if (_M_need & _ChronoParts::_Year)
+ if ((_M_need & _ChronoParts::_Year) != 0)
{
if (!__y.ok()) [[unlikely]]
__err |= ios_base::failbit;
@@ -4415,7 +5246,7 @@ namespace __detail
else if (__y == __bad_y)
__y = 1972y; // Leap year so that Feb 29 is valid.
- if (_M_need & _ChronoParts::_Month)
+ if ((_M_need & _ChronoParts::_Month) != 0)
{
if (!__m.ok()) [[unlikely]]
__err |= ios_base::failbit;
@@ -4423,7 +5254,7 @@ namespace __detail
else if (__m == __bad_mon)
__m = January;
- if (_M_need & _ChronoParts::_Day)
+ if ((_M_need & _ChronoParts::_Day) != 0)
{
if (__d < day(1) || __d > (__y/__m/last).day())
__err |= ios_base::failbit;
diff --git a/libstdc++-v3/include/bits/cpyfunc_impl.h b/libstdc++-v3/include/bits/cpyfunc_impl.h
new file mode 100644
index 0000000..f1918dd
--- /dev/null
+++ b/libstdc++-v3/include/bits/cpyfunc_impl.h
@@ -0,0 +1,273 @@
+// Implementation of std::copyable_function -*- 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/bits/cpyfunc_impl.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{functional}
+ */
+
+#ifndef _GLIBCXX_MOF_CV
+# define _GLIBCXX_MOF_CV
+#endif
+
+#ifdef _GLIBCXX_MOF_REF
+# define _GLIBCXX_MOF_INV_QUALS _GLIBCXX_MOF_CV _GLIBCXX_MOF_REF
+#else
+# define _GLIBCXX_MOF_REF
+# define _GLIBCXX_MOF_INV_QUALS _GLIBCXX_MOF_CV &
+#endif
+
+#define _GLIBCXX_MOF_CV_REF _GLIBCXX_MOF_CV _GLIBCXX_MOF_REF
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ /**
+ * @brief Polymorphic copyable function wrapper.
+ * @ingroup functors
+ * @since C++26
+ * @headerfile functional
+ *
+ * The `std::copyable_function` class template is a call wrapper similar
+ * to `std::function`, but it does not provide information about it's
+ * target, and preserves constness.
+ *
+ * It also supports const-qualification, ref-qualification, and
+ * no-throw guarantees. The qualifications and exception-specification
+ * of the `copyable_function::operator()` member function are respected
+ * when invoking the target function.
+ */
+ template<typename _Res, typename... _ArgTypes, bool _Noex>
+ class copyable_function<_Res(_ArgTypes...) _GLIBCXX_MOF_CV
+ _GLIBCXX_MOF_REF noexcept(_Noex)>
+ : __polyfunc::_Cpy_base
+ {
+ static_assert(
+ (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>()) && ...),
+ "each parameter type must be a complete class");
+
+ using _Base = __polyfunc::_Cpy_base;
+ using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>;
+ using _Signature = _Invoker::_Signature;
+
+ template<typename _Tp>
+ using __callable
+ = __conditional_t<_Noex,
+ is_nothrow_invocable_r<_Res, _Tp, _ArgTypes...>,
+ is_invocable_r<_Res, _Tp, _ArgTypes...>>;
+
+ // [func.wrap.copy.con]/1 is-callable-from<VT>
+ template<typename _Vt>
+ static constexpr bool __is_callable_from
+ = __and_v<__callable<_Vt _GLIBCXX_MOF_CV_REF>,
+ __callable<_Vt _GLIBCXX_MOF_INV_QUALS>>;
+
+ public:
+ using result_type = _Res;
+
+ /// Creates an empty object.
+ copyable_function() noexcept { }
+
+ /// Creates an empty object.
+ copyable_function(nullptr_t) noexcept { }
+
+ /// Moves the target object, leaving the source empty.
+ copyable_function(copyable_function&& __x) noexcept
+ : _Base(static_cast<_Base&&>(__x)),
+ _M_invoke(std::__exchange(__x._M_invoke, nullptr))
+ { }
+
+ /// Copies the target object.
+ copyable_function(copyable_function const& __x)
+ : _Base(static_cast<const _Base&>(__x)),
+ _M_invoke(__x._M_invoke)
+ { }
+
+ /// Stores a target object initialized from the argument.
+ template<typename _Fn, typename _Vt = decay_t<_Fn>>
+ requires (!is_same_v<_Vt, copyable_function>)
+ && (!__is_in_place_type_v<_Vt>) && __is_callable_from<_Vt>
+ copyable_function(_Fn&& __f) noexcept(_S_nothrow_init<_Vt, _Fn>())
+ {
+ static_assert(is_copy_constructible_v<_Vt>);
+ if constexpr (is_function_v<remove_pointer_t<_Vt>>
+ || is_member_pointer_v<_Vt>
+ || __is_polymorphic_function_v<_Vt>)
+ {
+ if (__f == nullptr)
+ return;
+ }
+
+ if constexpr (!__is_polymorphic_function_v<_Vt>
+ || !__polyfunc::__is_invoker_convertible<_Vt, copyable_function>())
+ {
+ _M_init<_Vt>(std::forward<_Fn>(__f));
+ _M_invoke = _Invoker::template _S_storage<_Vt _GLIBCXX_MOF_INV_QUALS>();
+ }
+ else if constexpr (is_lvalue_reference_v<_Fn>)
+ {
+ _M_copy(__polyfunc::__base_of(__f));
+ _M_invoke = __polyfunc::__invoker_of(__f);
+ }
+ else
+ {
+ _M_move(__polyfunc::__base_of(__f));
+ _M_invoke = std::__exchange(__polyfunc::__invoker_of(__f), nullptr);
+ }
+ }
+
+ /// Stores a target object initialized from the arguments.
+ template<typename _Tp, typename... _Args>
+ requires is_constructible_v<_Tp, _Args...>
+ && __is_callable_from<_Tp>
+ explicit
+ copyable_function(in_place_type_t<_Tp>, _Args&&... __args)
+ noexcept(_S_nothrow_init<_Tp, _Args...>())
+ : _M_invoke(_Invoker::template _S_storage<_Tp _GLIBCXX_MOF_INV_QUALS>())
+ {
+ static_assert(is_same_v<decay_t<_Tp>, _Tp>);
+ static_assert(is_copy_constructible_v<_Tp>);
+ _M_init<_Tp>(std::forward<_Args>(__args)...);
+ }
+
+ /// Stores a target object initialized from the arguments.
+ template<typename _Tp, typename _Up, typename... _Args>
+ requires is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
+ && __is_callable_from<_Tp>
+ explicit
+ copyable_function(in_place_type_t<_Tp>, initializer_list<_Up> __il,
+ _Args&&... __args)
+ noexcept(_S_nothrow_init<_Tp, initializer_list<_Up>&, _Args...>())
+ : _M_invoke(_Invoker::template _S_storage<_Tp _GLIBCXX_MOF_INV_QUALS>())
+ {
+ static_assert(is_same_v<decay_t<_Tp>, _Tp>);
+ static_assert(is_copy_constructible_v<_Tp>);
+ _M_init<_Tp>(__il, std::forward<_Args>(__args)...);
+ }
+
+ /// Stores a new target object, leaving `x` empty.
+ copyable_function&
+ operator=(copyable_function&& __x) noexcept
+ {
+ // Standard requires support of self assigment, by specifying it as
+ // copy and swap.
+ if (this != std::addressof(__x)) [[likely]]
+ {
+ _Base::operator=(static_cast<_Base&&>(__x));
+ _M_invoke = std::__exchange(__x._M_invoke, nullptr);
+ }
+ return *this;
+ }
+
+ /// Stores a copy of the source target object
+ copyable_function&
+ operator=(const copyable_function& __x)
+ {
+ copyable_function(__x).swap(*this);
+ return *this;
+ }
+
+ /// Destroys the target object (if any).
+ copyable_function&
+ operator=(nullptr_t) noexcept
+ {
+ _M_reset();
+ _M_invoke = nullptr;
+ return *this;
+ }
+
+ /// Stores a new target object, initialized from the argument.
+ template<typename _Fn>
+ requires is_constructible_v<copyable_function, _Fn>
+ copyable_function&
+ operator=(_Fn&& __f)
+ noexcept(is_nothrow_constructible_v<copyable_function, _Fn>)
+ {
+ copyable_function(std::forward<_Fn>(__f)).swap(*this);
+ return *this;
+ }
+
+ ~copyable_function() = default;
+
+ /// True if a target object is present, false otherwise.
+ explicit operator bool() const noexcept
+ { return _M_invoke != nullptr; }
+
+ /** Invoke the target object.
+ *
+ * The target object will be invoked using the supplied arguments,
+ * and as an lvalue or rvalue, and as const or non-const, as dictated
+ * by the template arguments of the `copyable_function` specialization.
+ *
+ * @pre Must not be empty.
+ */
+ _Res
+ operator()(_ArgTypes... __args) _GLIBCXX_MOF_CV_REF noexcept(_Noex)
+ {
+ __glibcxx_assert(*this != nullptr);
+ return _M_invoke(this->_M_storage, std::forward<_ArgTypes>(__args)...);
+ }
+
+ /// Exchange the target objects (if any).
+ void
+ swap(copyable_function& __x) noexcept
+ {
+ _Base::swap(__x);
+ std::swap(_M_invoke, __x._M_invoke);
+ }
+
+ /// Exchange the target objects (if any).
+ friend void
+ swap(copyable_function& __x, copyable_function& __y) noexcept
+ { __x.swap(__y); }
+
+ /// Check for emptiness by comparing with `nullptr`.
+ friend bool
+ operator==(const copyable_function& __x, nullptr_t) noexcept
+ { return __x._M_invoke == nullptr; }
+
+ private:
+ typename _Invoker::__storage_func_t _M_invoke = nullptr;
+
+ template<typename _Func>
+ friend auto&
+ __polyfunc::__invoker_of(_Func&) noexcept;
+
+ template<typename _Func>
+ friend auto&
+ __polyfunc::__base_of(_Func&) noexcept;
+
+ template<typename _Dst, typename _Src>
+ friend consteval bool
+ __polyfunc::__is_invoker_convertible() noexcept;
+ };
+
+#undef _GLIBCXX_MOF_CV_REF
+#undef _GLIBCXX_MOF_CV
+#undef _GLIBCXX_MOF_REF
+#undef _GLIBCXX_MOF_INV_QUALS
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
diff --git a/libstdc++-v3/include/bits/formatfwd.h b/libstdc++-v3/include/bits/formatfwd.h
index 3fa01ad..314b55d 100644
--- a/libstdc++-v3/include/bits/formatfwd.h
+++ b/libstdc++-v3/include/bits/formatfwd.h
@@ -71,12 +71,13 @@ namespace __format
concept __char = same_as<_CharT, char>;
#endif
- enum _Align {
+ enum class _Align : unsigned char {
_Align_default,
_Align_left,
_Align_right,
_Align_centre,
};
+ using enum _Align;
template<typename _CharT> struct _Spec;
@@ -161,6 +162,32 @@ namespace __format
using __maybe_const
= __conditional_t<formattable<const _Tp, _CharT>, const _Tp, _Tp>;
}
+
+ // [format.range], formatting of ranges
+ // [format.range.fmtkind], variable template format_kind
+ enum class range_format {
+ disabled,
+ map,
+ set,
+ sequence,
+ string,
+ debug_string
+ };
+
+ /** @brief A constant determining how a range should be formatted.
+ *
+ * The primary template of `std::format_kind` cannot be instantiated.
+ * There is a partial specialization for input ranges and you can
+ * specialize the variable template for your own cv-unqualified types
+ * that satisfy the `ranges::input_range` concept.
+ *
+ * @since C++23
+ */
+ template<typename _Rg>
+ constexpr auto format_kind = []{
+ static_assert(false, "cannot use primary template of 'std::format_kind'");
+ return type_identity<_Rg>{};
+ }();
#endif // format_ranges
_GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/include/bits/funcref_impl.h b/libstdc++-v3/include/bits/funcref_impl.h
new file mode 100644
index 0000000..44c9922
--- /dev/null
+++ b/libstdc++-v3/include/bits/funcref_impl.h
@@ -0,0 +1,202 @@
+// Implementation of std::function_ref -*- 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/bits/funcref_impl.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{functional}
+ */
+
+#ifndef _GLIBCXX_MOF_CV
+# define _GLIBCXX_MOF_CV
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ /// @cond undocumented
+ namespace __polyfunc
+ {
+ template<bool _Noex, typename _Ret, typename _Class, typename... _Args>
+ struct __skip_first_arg<_Ret(_Class::*)(_Args...) _GLIBCXX_MOF_CV
+ noexcept(_Noex)>
+ { using type = _Ret(_Args...) noexcept(_Noex); };
+
+ template<bool _Noex, typename _Ret, typename _Class, typename... _Args>
+ struct __skip_first_arg<_Ret(_Class::*)(_Args...) _GLIBCXX_MOF_CV&
+ noexcept(_Noex)>
+ { using type = _Ret(_Args...) noexcept(_Noex); };
+ } // namespace __polyfunc
+ /// @endcond
+
+ /**
+ * @brief Non-owning polymorphic function wrapper.
+ * @ingroup functors
+ * @since C++26
+ * @headerfile functional
+ *
+ * The `std::function_ref` class template is a non-owning call wrapper,
+ * that refers to a bound object. Using function_ref outside of the lifetime
+ * of the bound object has undefined behavior.
+ *
+ * It supports const-qualification and no-throw guarantees. The
+ * qualifications and exception-specification of the signature are respected
+ * when invoking the reference function.
+ */
+ template<typename _Res, typename... _ArgTypes, bool _Noex>
+ class function_ref<_Res(_ArgTypes...) _GLIBCXX_MOF_CV
+ noexcept(_Noex)>
+ {
+ static_assert(
+ (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>()) && ...),
+ "each parameter type must be a complete class");
+
+ using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>;
+ using _Signature = _Invoker::_Signature;
+
+ // [func.wrap.ref.ctor]/1 is-invokable-using
+ template<typename... _Tps>
+ static constexpr bool __is_invocable_using
+ = __conditional_t<_Noex,
+ is_nothrow_invocable_r<_Res, _Tps..., _ArgTypes...>,
+ is_invocable_r<_Res, _Tps..., _ArgTypes...>>::value;
+
+ public:
+ /// Target and bound object is function pointed by parameter.
+ template<typename _Fn>
+ requires is_function_v<_Fn> && __is_invocable_using<_Fn*>
+ function_ref(_Fn* __fn) noexcept
+ {
+ __glibcxx_assert(__fn != nullptr);
+ _M_invoke = _Invoker::template _S_ptrs<_Fn*>();
+ _M_init(__fn);
+ }
+
+ /// Target and bound object is object referenced by parameter.
+ template<typename _Fn, typename _Vt = remove_reference_t<_Fn>>
+ requires (!is_same_v<remove_cv_t<_Vt>, function_ref>)
+ && (!is_member_pointer_v<_Vt>)
+ // We deviate from standard by having this condition, that forces
+ // function references to use _Fn* constructors. This simplies
+ // implementation and provide better diagnostic when used in
+ // constant expression (above constructor is not constexpr).
+ && (!is_function_v<_Vt>)
+ && __is_invocable_using<_Vt _GLIBCXX_MOF_CV&>
+ constexpr
+ function_ref(_Fn&& __f) noexcept
+ {
+ _M_invoke = _Invoker::template _S_ptrs<_Vt _GLIBCXX_MOF_CV&>();
+ _M_init(std::addressof(__f));
+ }
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4256. Incorrect constrains for function_ref constructors from nontype
+ /// Target object is __fn. There is no bound object.
+ template<auto __fn>
+ requires __is_invocable_using<const decltype(__fn)&>
+ constexpr
+ function_ref(nontype_t<__fn>) noexcept
+ {
+ using _Fn = remove_cv_t<decltype(__fn)>;
+ if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+ static_assert(__fn != nullptr);
+
+ _M_invoke = &_Invoker::template _S_nttp<__fn>;
+ _M_ptrs._M_obj = nullptr;
+ }
+
+ /// Target object is equivalent to std::bind_front<_fn>(std::ref(__ref)).
+ /// Bound object is object referenced by second parameter.
+ template<auto __fn, typename _Up, typename _Td = remove_reference_t<_Up>>
+ requires (!is_rvalue_reference_v<_Up&&>)
+ && __is_invocable_using<const decltype(__fn)&, _Td _GLIBCXX_MOF_CV&>
+ constexpr
+ function_ref(nontype_t<__fn>, _Up&& __ref) noexcept
+ {
+ using _Fn = remove_cv_t<decltype(__fn)>;
+ if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+ static_assert(__fn != nullptr);
+
+ using _Tr = _Td _GLIBCXX_MOF_CV&;
+ if constexpr (is_member_pointer_v<_Fn> && is_lvalue_reference_v<_Tr>)
+ // N.B. invoking member pointer on lvalue produces the same effects,
+ // as invoking it on pointer to that lvalue.
+ _M_invoke = &_Invoker::template _S_bind_ptr<__fn, _Td _GLIBCXX_MOF_CV>;
+ else
+ _M_invoke = &_Invoker::template _S_bind_ref<__fn, _Tr>;
+ _M_init(std::addressof(__ref));
+ }
+
+ /// Target object is equivalent to std::bind_front<_fn>(__ptr).
+ /// Bound object is object pointed by second parameter (if any).
+ template<auto __fn, typename _Td>
+ requires __is_invocable_using<const decltype(__fn)&, _Td _GLIBCXX_MOF_CV*>
+ constexpr
+ function_ref(nontype_t<__fn>, _Td _GLIBCXX_MOF_CV* __ptr) noexcept
+ {
+ using _Fn = remove_cv_t<decltype(__fn)>;
+ if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+ static_assert(__fn != nullptr);
+ if constexpr (is_member_pointer_v<_Fn>)
+ __glibcxx_assert(__ptr != nullptr);
+
+ _M_invoke = &_Invoker::template _S_bind_ptr<__fn, _Td _GLIBCXX_MOF_CV>;
+ _M_init(__ptr);
+ }
+
+ template<typename _Tp>
+ requires (!is_same_v<_Tp, function_ref>)
+ && (!is_pointer_v<_Tp>) && (!__is_nontype_v<_Tp>)
+ function_ref&
+ operator=(_Tp) = delete;
+
+ /** Invoke the target object.
+ *
+ * The bound object will be invoked using the supplied arguments,
+ * and as const or non-const, as dictated by the template arguments
+ * of the `function_ref` specialization.
+ */
+ _Res
+ operator()(_ArgTypes... __args) const noexcept(_Noex)
+ { return _M_invoke(_M_ptrs, std::forward<_ArgTypes>(__args)...); }
+
+ private:
+ template<typename _Tp>
+ constexpr void
+ _M_init(_Tp* __ptr) noexcept
+ {
+ if constexpr (is_function_v<_Tp>)
+ _M_ptrs._M_func = reinterpret_cast<void(*)()>(__ptr);
+ else
+ _M_ptrs._M_obj = __ptr;
+ }
+
+ typename _Invoker::__ptrs_func_t _M_invoke;
+ __polyfunc::_Ptrs _M_ptrs;
+ };
+
+#undef _GLIBCXX_MOF_CV
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
diff --git a/libstdc++-v3/include/bits/funcwrap.h b/libstdc++-v3/include/bits/funcwrap.h
new file mode 100644
index 0000000..9db4ab7
--- /dev/null
+++ b/libstdc++-v3/include/bits/funcwrap.h
@@ -0,0 +1,621 @@
+// Implementation of std::move_only_function, std::copyable_function
+// and std::function_ref -*- 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/bits/funcwrap.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{functional}
+ */
+
+#ifndef _GLIBCXX_FUNCWRAP_H
+#define _GLIBCXX_FUNCWRAP_H 1
+
+#ifdef _GLIBCXX_SYSHDR
+#pragma GCC system_header
+#endif
+
+#include <bits/version.h>
+
+#if __glibcxx_move_only_function || __glibcxx_copyable_function || __glibcxx_function_ref
+
+#include <bits/invoke.h>
+#include <bits/utility.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ /// @cond undocumented
+ template<typename _Tp>
+ inline constexpr bool __is_polymorphic_function_v = false;
+
+ namespace __polyfunc
+ {
+ union _Ptrs
+ {
+ const void* _M_obj;
+ void (*_M_func)();
+ };
+
+ template<typename _Tp>
+ [[__gnu__::__always_inline__]]
+ constexpr auto*
+ __cast_to(_Ptrs __ptrs) noexcept
+ {
+ using _Td = remove_reference_t<_Tp>;
+ if constexpr (is_function_v<_Td>)
+ return reinterpret_cast<_Td*>(__ptrs._M_func);
+ else if constexpr (is_const_v<_Td>)
+ return static_cast<_Td*>(__ptrs._M_obj);
+ else
+ return static_cast<_Td*>(const_cast<void*>(__ptrs._M_obj));
+ }
+
+ struct _Storage
+ {
+ void* _M_addr() noexcept { return &_M_bytes[0]; }
+ void const* _M_addr() const noexcept { return &_M_bytes[0]; }
+
+ template<typename _Tp>
+ static consteval bool
+ _S_stored_locally() noexcept
+ {
+ return sizeof(_Tp) <= sizeof(_Storage)
+ && alignof(_Tp) <= alignof(_Storage)
+ && is_nothrow_move_constructible_v<_Tp>;
+ }
+
+ template<typename _Tp, typename... _Args>
+ static consteval bool
+ _S_nothrow_init() noexcept
+ {
+ if constexpr (_S_stored_locally<_Tp>())
+ return is_nothrow_constructible_v<_Tp, _Args...>;
+ return false;
+ }
+
+ template<typename _Tp, typename... _Args>
+ void
+ _M_init(_Args&&... __args) noexcept(_S_nothrow_init<_Tp, _Args...>())
+ {
+ if constexpr (is_function_v<remove_pointer_t<_Tp>>)
+ {
+ static_assert( sizeof...(__args) <= 1 );
+ // __args can have up to one element, returns nullptr if empty.
+ _Tp __func = (nullptr, ..., __args);
+ _M_ptrs._M_func = reinterpret_cast<void(*)()>(__func);
+ }
+ else if constexpr (!_S_stored_locally<_Tp>())
+ _M_ptrs._M_obj = new _Tp(std::forward<_Args>(__args)...);
+ else
+ ::new (_M_addr()) _Tp(std::forward<_Args>(__args)...);
+ }
+
+ // We want to have enough space to store a simple delegate type.
+ struct _Delegate { void (_Storage::*__pfm)(); _Storage* __obj; };
+ union {
+ _Ptrs _M_ptrs;
+ alignas(_Delegate) alignas(void(*)())
+ unsigned char _M_bytes[sizeof(_Delegate)];
+ };
+ };
+
+ template<bool _Noex, typename _Ret, typename... _Args>
+ struct _Base_invoker
+ {
+ using _Signature = _Ret(*)(_Args...) noexcept(_Noex);
+
+ using __storage_func_t = _Ret(*)(const _Storage&, _Args...) noexcept(_Noex);
+ template<typename _Tp>
+ static consteval __storage_func_t
+ _S_storage()
+ { return &_S_call_storage<_Adjust_target<_Tp>>; }
+
+ using __ptrs_func_t = _Ret(*)(_Ptrs, _Args...) noexcept(_Noex);
+ template<typename _Tp>
+ static consteval __ptrs_func_t
+ _S_ptrs()
+ { return &_S_call_ptrs<_Adjust_target<_Tp>>; }
+
+#ifdef __glibcxx_function_ref // C++ >= 26
+ template<auto __fn>
+ static _Ret
+ _S_nttp(_Ptrs, _Args... __args) noexcept(_Noex)
+ { return std::__invoke_r<_Ret>(__fn, std::forward<_Args>(__args)...); }
+
+ template<auto __fn, typename _Tp>
+ static _Ret
+ _S_bind_ptr(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
+ {
+ auto* __p = __polyfunc::__cast_to<_Tp>(__ptrs);
+ return std::__invoke_r<_Ret>(__fn, __p,
+ std::forward<_Args>(__args)...);
+ }
+
+ template<auto __fn, typename _Ref>
+ static _Ret
+ _S_bind_ref(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
+ {
+ auto* __p = __polyfunc::__cast_to<_Ref>(__ptrs);
+ return std::__invoke_r<_Ret>(__fn, static_cast<_Ref>(*__p),
+ std::forward<_Args>(__args)...);
+ }
+#endif // __glibcxx_function_ref
+
+ private:
+ template<typename _Tp, typename _Td = remove_cvref_t<_Tp>>
+ using _Adjust_target =
+ __conditional_t<is_pointer_v<_Td> || is_member_pointer_v<_Td>, _Td, _Tp>;
+
+ template<typename _Tp>
+ static _Ret
+ _S_call_storage(const _Storage& __ref, _Args... __args) noexcept(_Noex)
+ {
+ _Ptrs __ptrs;
+ if constexpr (is_function_v<remove_pointer_t<_Tp>>)
+ __ptrs._M_func = __ref._M_ptrs._M_func;
+ else if constexpr (!_Storage::_S_stored_locally<remove_cvref_t<_Tp>>())
+ __ptrs._M_obj = __ref._M_ptrs._M_obj;
+ else
+ __ptrs._M_obj = __ref._M_addr();
+ return _S_call_ptrs<_Tp>(__ptrs, std::forward<_Args>(__args)...);
+ }
+
+ template<typename _Tp>
+ static _Ret
+ _S_call_ptrs(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
+ {
+ if constexpr (is_function_v<remove_pointer_t<_Tp>>)
+ return std::__invoke_r<_Ret>(reinterpret_cast<_Tp>(__ptrs._M_func),
+ std::forward<_Args>(__args)...);
+ else
+ {
+ auto* __p = __polyfunc::__cast_to<_Tp>(__ptrs);
+ return std::__invoke_r<_Ret>(static_cast<_Tp>(*__p),
+ std::forward<_Args>(__args)...);
+ }
+ }
+ };
+
+ template<typename _Tp>
+ consteval bool
+ __pass_by_value()
+ {
+ // n.b. sizeof(Incomplete&) is ill-formed for incomplete types,
+ // so we check is_reference_v first.
+ if constexpr (is_reference_v<_Tp> || is_scalar_v<_Tp>)
+ return true;
+ else
+ // n.b. we already asserted that types are complete in wrappers,
+ // avoid triggering additional errors from this function.
+ if constexpr (std::__is_complete_or_unbounded(__type_identity<_Tp>()))
+ if constexpr (sizeof(_Tp) <= 2 * sizeof(void*))
+ return is_trivially_move_constructible_v<_Tp>
+ && is_trivially_destructible_v<_Tp>;
+ return false;
+ }
+
+ template<typename _Tp>
+ using __param_t = __conditional_t<__pass_by_value<_Tp>(), _Tp, _Tp&&>;
+
+ template<bool _Noex, typename _Ret, typename... _Args>
+ using _Invoker = _Base_invoker<_Noex, remove_cv_t<_Ret>, __param_t<_Args>...>;
+
+ template<typename _Func>
+ auto&
+ __invoker_of(_Func& __f) noexcept
+ { return __f._M_invoke; }
+
+ template<typename _Func>
+ auto&
+ __base_of(_Func& __f) noexcept
+ { return static_cast<__like_t<_Func&, typename _Func::_Base>>(__f); }
+
+ template<typename _Src, typename _Dst>
+ consteval bool
+ __is_invoker_convertible() noexcept
+ {
+ if constexpr (requires { typename _Src::_Signature; })
+ return is_convertible_v<typename _Src::_Signature,
+ typename _Dst::_Signature>;
+ else
+ return false;
+ }
+
+#if __glibcxx_move_only_function || __glibcxx_copyable_function
+ struct _Manager
+ {
+ enum class _Op
+ {
+ // saves address of entity in *__src to __target._M_ptrs,
+ _Address,
+ // moves entity stored in *__src to __target, __src becomes empty
+ _Move,
+ // copies entity stored in *__src to __target, supported only if
+ // _ProvideCopy is specified.
+ _Copy,
+ // destroys entity stored in __target, __src is ignoring
+ _Destroy,
+ };
+
+ // A function that performs operation __op on the __target and possibly __src.
+ using _Func = void (*)(_Op __op, _Storage& __target, const _Storage* __src);
+
+ // The no-op manager function for objects with no target.
+ static void _S_empty(_Op, _Storage&, const _Storage*) noexcept { }
+
+ template<bool _ProvideCopy, typename _Tp>
+ consteval static auto
+ _S_select()
+ {
+ if constexpr (is_function_v<remove_pointer_t<_Tp>>)
+ return &_S_func;
+ else if constexpr (!_Storage::_S_stored_locally<_Tp>())
+ return &_S_ptr<_ProvideCopy, _Tp>;
+ else if constexpr (is_trivially_copyable_v<_Tp>)
+ return &_S_trivial;
+ else
+ return &_S_local<_ProvideCopy, _Tp>;
+ }
+
+ private:
+ static void
+ _S_func(_Op __op, _Storage& __target, const _Storage* __src) noexcept
+ {
+ switch (__op)
+ {
+ case _Op::_Address:
+ case _Op::_Move:
+ case _Op::_Copy:
+ __target._M_ptrs._M_func = __src->_M_ptrs._M_func;
+ return;
+ case _Op::_Destroy:
+ return;
+ }
+ }
+
+ static void
+ _S_trivial(_Op __op, _Storage& __target, const _Storage* __src) noexcept
+ {
+ switch (__op)
+ {
+ case _Op::_Address:
+ __target._M_ptrs._M_obj = __src->_M_addr();
+ return;
+ case _Op::_Move:
+ case _Op::_Copy:
+ // N.B. Creating _Storage starts lifetime of _M_bytes char array,
+ // that implicitly creates, amongst other, all possible trivially
+ // copyable objects, so we copy any object present in __src._M_bytes.
+ ::new (&__target) _Storage(*__src);
+ return;
+ case _Op::_Destroy:
+ return;
+ }
+ }
+
+ template<bool _Provide_copy, typename _Tp>
+ static void
+ _S_local(_Op __op, _Storage& __target, const _Storage* __src)
+ noexcept(!_Provide_copy)
+ {
+ switch (__op)
+ {
+ case _Op::_Address:
+ __target._M_ptrs._M_obj = __src->_M_addr();
+ return;
+ case _Op::_Move:
+ {
+ _Tp* __obj = static_cast<_Tp*>(const_cast<void*>(__src->_M_addr()));
+ ::new(__target._M_addr()) _Tp(std::move(*__obj));
+ __obj->~_Tp();
+ }
+ return;
+ case _Op::_Destroy:
+ static_cast<_Tp*>(__target._M_addr())->~_Tp();
+ return;
+ case _Op::_Copy:
+ if constexpr (_Provide_copy)
+ {
+ auto* __obj = static_cast<const _Tp*>(__src->_M_addr());
+ ::new (__target._M_addr()) _Tp(*__obj);
+ return;
+ }
+ __builtin_unreachable();
+ }
+ }
+
+ template<bool _Provide_copy, typename _Tp>
+ static void
+ _S_ptr(_Op __op, _Storage& __target, const _Storage* __src)
+ noexcept(!_Provide_copy)
+ {
+ switch (__op)
+ {
+ case _Op::_Address:
+ case _Op::_Move:
+ __target._M_ptrs._M_obj = __src->_M_ptrs._M_obj;
+ return;
+ case _Op::_Destroy:
+ delete static_cast<const _Tp*>(__target._M_ptrs._M_obj);
+ return;
+ case _Op::_Copy:
+ if constexpr (_Provide_copy)
+ {
+ auto* __obj = static_cast<const _Tp*>(__src->_M_ptrs._M_obj);
+ __target._M_ptrs._M_obj = new _Tp(*__obj);
+ return;
+ }
+ __builtin_unreachable();
+ }
+ }
+ };
+
+ class _Mo_base
+ {
+ protected:
+ _Mo_base() noexcept
+ : _M_manage(_Manager::_S_empty)
+ { }
+
+ _Mo_base(_Mo_base&& __x) noexcept
+ { _M_move(__x); }
+
+ template<typename _Tp, typename... _Args>
+ static consteval bool
+ _S_nothrow_init() noexcept
+ { return _Storage::_S_nothrow_init<_Tp, _Args...>(); }
+
+ template<typename _Tp, typename... _Args>
+ void
+ _M_init(_Args&&... __args)
+ noexcept(_S_nothrow_init<_Tp, _Args...>())
+ {
+ _M_storage._M_init<_Tp>(std::forward<_Args>(__args)...);
+ _M_manage = _Manager::_S_select<false, _Tp>();
+ }
+
+ void
+ _M_move(_Mo_base& __x) noexcept
+ {
+ using _Op = _Manager::_Op;
+ _M_manage = std::__exchange(__x._M_manage, _Manager::_S_empty);
+ _M_manage(_Op::_Move, _M_storage, &__x._M_storage);
+ }
+
+ _Mo_base&
+ operator=(_Mo_base&& __x) noexcept
+ {
+ _M_destroy();
+ _M_move(__x);
+ return *this;
+ }
+
+ void
+ _M_reset() noexcept
+ {
+ _M_destroy();
+ _M_manage = _Manager::_S_empty;
+ }
+
+ ~_Mo_base()
+ { _M_destroy(); }
+
+ void
+ swap(_Mo_base& __x) noexcept
+ {
+ using _Op = _Manager::_Op;
+ // Order of operations here is more efficient if __x is empty.
+ _Storage __s;
+ __x._M_manage(_Op::_Move, __s, &__x._M_storage);
+ _M_manage(_Op::_Move, __x._M_storage, &_M_storage);
+ __x._M_manage(_Op::_Move, _M_storage, &__s);
+ std::swap(_M_manage, __x._M_manage);
+ }
+
+ _Storage _M_storage;
+
+ private:
+ void _M_destroy() noexcept
+ { _M_manage(_Manager::_Op::_Destroy, _M_storage, nullptr); }
+
+ _Manager::_Func _M_manage;
+
+#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
+ friend class _Cpy_base;
+#endif // __glibcxx_copyable_function
+ };
+#endif // __glibcxx_copyable_function || __glibcxx_copyable_function
+} // namespace __polyfunc
+ /// @endcond
+
+#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
+ template<typename... _Signature>
+ class move_only_function; // not defined
+
+ /// @cond undocumented
+ template<typename _Tp>
+ constexpr bool __is_polymorphic_function_v<move_only_function<_Tp>> = true;
+
+ namespace __detail::__variant
+ {
+ template<typename> struct _Never_valueless_alt; // see <variant>
+
+ // Provide the strong exception-safety guarantee when emplacing a
+ // move_only_function into a variant.
+ template<typename... _Signature>
+ struct _Never_valueless_alt<std::move_only_function<_Signature...>>
+ : true_type
+ { };
+ } // namespace __detail::__variant
+ /// @endcond
+#endif // __glibcxx_move_only_function
+
+#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
+ /// @cond undocumented
+ namespace __polyfunc
+ {
+ class _Cpy_base : public _Mo_base
+ {
+ protected:
+ _Cpy_base() = default;
+
+ template<typename _Tp, typename... _Args>
+ void
+ _M_init(_Args&&... __args)
+ noexcept(_S_nothrow_init<_Tp, _Args...>())
+ {
+ _M_storage._M_init<_Tp>(std::forward<_Args>(__args)...);
+ _M_manage = _Manager::_S_select<true, _Tp>();
+ }
+
+ void
+ _M_copy(_Cpy_base const& __x)
+ {
+ using _Op = _Manager::_Op;
+ __x._M_manage(_Op::_Copy, _M_storage, &__x._M_storage);
+ _M_manage = __x._M_manage;
+ }
+
+ _Cpy_base(_Cpy_base&&) = default;
+
+ _Cpy_base(_Cpy_base const& __x)
+ { _M_copy(__x); }
+
+ _Cpy_base&
+ operator=(_Cpy_base&&) = default;
+
+ _Cpy_base&
+ // Needs to use copy and swap for exception guarantees.
+ operator=(_Cpy_base const&) = delete;
+ };
+ } // namespace __polyfunc
+ /// @endcond
+
+ template<typename... _Signature>
+ class copyable_function; // not defined
+
+ template<typename _Tp>
+ constexpr bool __is_polymorphic_function_v<copyable_function<_Tp>> = true;
+
+ namespace __detail::__variant
+ {
+ template<typename> struct _Never_valueless_alt; // see <variant>
+
+ // Provide the strong exception-safety guarantee when emplacing a
+ // copyable_function into a variant.
+ template<typename... _Signature>
+ struct _Never_valueless_alt<std::copyable_function<_Signature...>>
+ : true_type
+ { };
+ } // namespace __detail::__variant
+#endif // __glibcxx_copyable_function
+
+#ifdef __glibcxx_function_ref // C++ >= 26
+ /// @cond undocumented
+ namespace __polyfunc
+ {
+ template<typename _Sig>
+ struct __skip_first_arg;
+
+ // Additional partial specializations are defined in bits/funcref_impl.h
+ template<bool _Noex, typename _Ret, typename _Arg, typename... _Args>
+ struct __skip_first_arg<_Ret(*)(_Arg, _Args...) noexcept(_Noex)>
+ { using type = _Ret(_Args...) noexcept(_Noex); };
+
+ template<typename _Fn, typename _Tr>
+ consteval auto
+ __deduce_funcref()
+ {
+ if constexpr (is_member_object_pointer_v<_Fn>)
+ // TODO Consider reporting issue to make this noexcept
+ return static_cast<invoke_result_t<_Fn, _Tr>(*)()>(nullptr);
+ else
+ return static_cast<__skip_first_arg<_Fn>::type*>(nullptr);
+ }
+ } // namespace __polyfunc
+ /// @endcond
+
+ template<typename... _Signature>
+ class function_ref; // not defined
+
+ template<typename _Fn>
+ requires is_function_v<_Fn>
+ function_ref(_Fn*) -> function_ref<_Fn>;
+
+ template<auto __f, class _Fn = remove_pointer_t<decltype(__f)>>
+ requires is_function_v<_Fn>
+ function_ref(nontype_t<__f>) -> function_ref<_Fn>;
+
+ template<auto __f, typename _Tp, class _Fn = decltype(__f)>
+ requires is_member_pointer_v<_Fn> || is_function_v<remove_pointer_t<_Fn>>
+ function_ref(nontype_t<__f>, _Tp&&)
+ -> function_ref<
+ remove_pointer_t<decltype(__polyfunc::__deduce_funcref<_Fn, _Tp&>())>>;
+
+#endif // __glibcxx_function_ref
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
+#include "mofunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#include "mofunc_impl.h"
+#define _GLIBCXX_MOF_REF &
+#include "mofunc_impl.h"
+#define _GLIBCXX_MOF_REF &&
+#include "mofunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#define _GLIBCXX_MOF_REF &
+#include "mofunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#define _GLIBCXX_MOF_REF &&
+#include "mofunc_impl.h"
+#endif // __glibcxx_move_only_function
+
+#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
+#include "cpyfunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#include "cpyfunc_impl.h"
+#define _GLIBCXX_MOF_REF &
+#include "cpyfunc_impl.h"
+#define _GLIBCXX_MOF_REF &&
+#include "cpyfunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#define _GLIBCXX_MOF_REF &
+#include "cpyfunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#define _GLIBCXX_MOF_REF &&
+#include "cpyfunc_impl.h"
+#endif // __glibcxx_copyable_function
+
+#ifdef __glibcxx_function_ref // C++ >= 26
+#include "funcref_impl.h"
+#define _GLIBCXX_MOF_CV const
+#include "funcref_impl.h"
+#endif // __glibcxx_function_ref
+
+#endif // move_only_function || copyable_function || function_ref
+#endif // _GLIBCXX_FUNCWRAP_H
diff --git a/libstdc++-v3/include/bits/indirect.h b/libstdc++-v3/include/bits/indirect.h
new file mode 100644
index 0000000..e8000d7
--- /dev/null
+++ b/libstdc++-v3/include/bits/indirect.h
@@ -0,0 +1,833 @@
+// Vocabulary Types for Composite Class Design -*- 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/bits/indirect.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{memory}
+ */
+
+#ifndef _GLIBCXX_INDIRECT_H
+#define _GLIBCXX_INDIRECT_H 1
+
+#pragma GCC system_header
+
+#include <bits/version.h>
+
+#if __glibcxx_indirect || __glibcxx_polymorphic // >= C++26
+#include <compare>
+#include <initializer_list>
+#include <bits/allocator.h>
+#include <bits/alloc_traits.h>
+#include <bits/allocated_ptr.h> // __allocate_guarded
+#include <bits/uses_allocator.h> // allocator_arg_t
+#include <bits/utility.h> // __is_in_place_type_v
+#include <bits/functional_hash.h> // hash
+#include <bits/memory_resource.h> // polymorphic_allocator
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#if __glibcxx_indirect
+ template<typename _Tp, typename _Alloc = allocator<_Tp>>
+ class indirect;
+
+ template<typename _Tp>
+ constexpr bool __is_indirect = false;
+ template<typename _Tp, typename _Alloc>
+ constexpr bool __is_indirect<indirect<_Tp, _Alloc>> = true;
+
+#if _GLIBCXX_HOSTED
+ namespace pmr
+ {
+ template<typename _Tp>
+ using indirect = indirect<_Tp, polymorphic_allocator<_Tp>>;
+ }
+#endif
+
+ // [indirect], class template indirect
+ template<typename _Tp, typename _Alloc>
+ class indirect
+ {
+ static_assert(is_object_v<_Tp>);
+ static_assert(!is_array_v<_Tp>);
+ static_assert(!is_same_v<_Tp, in_place_t>);
+ static_assert(!__is_in_place_type_v<_Tp>);
+ static_assert(!is_const_v<_Tp> && !is_volatile_v<_Tp>);
+
+ using _ATraits = allocator_traits<_Alloc>;
+ static_assert(is_same_v<_Tp, typename _ATraits::value_type>);
+
+ public:
+ using value_type = _Tp;
+ using allocator_type = _Alloc;
+ using pointer = typename allocator_traits<_Alloc>::pointer;
+ using const_pointer = typename allocator_traits<_Alloc>::const_pointer;
+
+ constexpr explicit
+ indirect() requires is_default_constructible_v<_Alloc>
+ : _M_objp(_M_make_obj_chk())
+ { }
+
+ constexpr explicit
+ indirect(allocator_arg_t, const _Alloc& __a)
+ : _M_alloc(__a), _M_objp(_M_make_obj_chk())
+ { }
+
+ constexpr
+ indirect(const indirect& __o)
+ : indirect(allocator_arg,
+ _ATraits::select_on_container_copy_construction(__o._M_alloc),
+ __o)
+ { }
+
+ constexpr
+ indirect(allocator_arg_t, const _Alloc& __a, const indirect& __other)
+ : _M_alloc(__a)
+ {
+ if (__other._M_objp)
+ _M_objp = _M_make_obj_chk(__other.__get());
+ else
+ _M_objp = nullptr;
+ }
+
+ constexpr
+ indirect(indirect&& __other) noexcept
+ : _M_alloc(std::move(__other._M_alloc)),
+ _M_objp(std::__exchange(__other._M_objp, nullptr))
+ { }
+
+ constexpr
+ indirect(allocator_arg_t, const _Alloc& __a,
+ indirect&& __other) noexcept(_ATraits::is_always_equal::value)
+ : _M_alloc(__a),
+ _M_objp(std::__exchange(__other._M_objp, nullptr))
+ {
+ if constexpr (!_ATraits::is_always_equal::value)
+ if (_M_objp && _M_alloc != __other._M_alloc)
+ {
+ static_assert(sizeof(_Tp) != 0, "must be a complete type");
+
+ // _M_alloc cannot free _M_objp, give it back to __other.
+ __other._M_objp = std::__exchange(_M_objp, nullptr);
+ // And create a new object that can be freed by _M_alloc.
+ _M_objp = _M_make_obj(std::move(*__other._M_objp));
+ }
+ }
+
+ template<typename _Up = _Tp>
+ requires (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
+ && (!is_same_v<remove_cvref_t<_Up>, indirect>)
+ && is_constructible_v<_Tp, _Up>
+ && is_default_constructible_v<_Alloc>
+ constexpr explicit
+ indirect(_Up&& __u)
+ : _M_objp(_M_make_obj(std::forward<_Up>(__u)))
+ { }
+
+ template<typename _Up = _Tp>
+ requires (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
+ && (!is_same_v<remove_cvref_t<_Up>, indirect>)
+ && is_constructible_v<_Tp, _Up>
+ constexpr explicit
+ indirect(allocator_arg_t, const _Alloc& __a, _Up&& __u)
+ : _M_alloc(__a), _M_objp(_M_make_obj(std::forward<_Up>(__u)))
+ { }
+
+ template<typename... _Us>
+ requires is_constructible_v<_Tp, _Us...>
+ && is_default_constructible_v<_Alloc>
+ constexpr explicit
+ indirect(in_place_t, _Us&&... __us)
+ : _M_objp(_M_make_obj(std::forward<_Us>(__us)...))
+ { }
+
+ template<typename... _Us>
+ requires is_constructible_v<_Tp, _Us...>
+ constexpr explicit
+ indirect(allocator_arg_t, const _Alloc& __a, in_place_t, _Us&&... __us)
+ : _M_alloc(__a),
+ _M_objp(_M_make_obj(std::forward<_Us>(__us)...))
+ { }
+
+ template<typename _Ip, typename... _Us>
+ requires is_constructible_v<_Tp, initializer_list<_Ip>&, _Us...>
+ && is_default_constructible_v<_Alloc>
+ constexpr explicit
+ indirect(in_place_t, initializer_list<_Ip> __il, _Us&&... __us)
+ : _M_objp(_M_make_obj(__il, std::forward<_Us>(__us)...))
+ { }
+
+ template<typename _Ip, typename... _Us>
+ requires is_constructible_v<_Tp, initializer_list<_Ip>&, _Us...>
+ constexpr explicit
+ indirect(allocator_arg_t, const _Alloc& __a,
+ in_place_t, initializer_list<_Ip> __il, _Us&&... __us)
+ : _M_alloc(__a),
+ _M_objp(_M_make_obj(__il, std::forward<_Us>(__us)...))
+ { }
+
+ constexpr ~indirect()
+ {
+ static_assert(sizeof(_Tp) != 0, "must be a complete type");
+ _M_reset(nullptr);
+ }
+
+ constexpr indirect&
+ operator=(const indirect& __other)
+ {
+ static_assert(is_copy_assignable_v<_Tp>);
+ static_assert(is_copy_constructible_v<_Tp>);
+
+ if (__builtin_addressof(__other) == this) [[unlikely]]
+ return *this;
+
+ constexpr bool __pocca
+ = _ATraits::propagate_on_container_copy_assignment::value;
+
+ pointer __ptr = nullptr;
+ if (__other._M_objp)
+ {
+ if (_ATraits::is_always_equal::value
+ || _M_alloc == __other._M_alloc)
+ {
+ if (_M_objp)
+ {
+ *_M_objp = __other.__get();
+ if constexpr (__pocca)
+ _M_alloc = __other._M_alloc;
+ return *this;
+ }
+ }
+ const indirect& __x = __pocca ? __other : *this;
+ __ptr = __x._M_make_obj(__other.__get());
+ }
+
+ _M_reset(__ptr);
+
+ if constexpr (__pocca)
+ _M_alloc = __other._M_alloc;
+
+ return *this;
+ }
+
+ constexpr indirect&
+ operator=(indirect&& __other)
+ noexcept(_ATraits::propagate_on_container_move_assignment::value
+ || _ATraits::is_always_equal::value)
+ {
+ // N5008 says is_copy_constructible_v<T> here, but that seems wrong.
+ // We only require move-constructible, and only for unequal allocators.
+
+ if (__builtin_addressof(__other) == this) [[unlikely]]
+ return *this;
+
+ constexpr bool __pocma
+ = _ATraits::propagate_on_container_move_assignment::value;
+
+ pointer __ptr = nullptr;
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4251. Move assignment for indirect unnecessarily requires copy construction
+ if constexpr (_ATraits::is_always_equal::value || __pocma)
+ __ptr = std::__exchange(__other._M_objp, nullptr);
+ else if (_M_alloc == __other._M_alloc)
+ __ptr = std::__exchange(__other._M_objp, nullptr);
+ else if (__other._M_objp)
+ {
+ static_assert(is_move_constructible_v<_Tp>);
+ __ptr = _M_make_obj(std::move(*__other._M_objp));
+ }
+
+ _M_reset(__ptr);
+
+ if constexpr (__pocma)
+ _M_alloc = __other._M_alloc;
+
+ return *this;
+ }
+
+ template<typename _Up = _Tp>
+ requires (!is_same_v<remove_cvref_t<_Up>, indirect>)
+ && is_constructible_v<_Tp, _Up> && is_assignable_v<_Tp&, _Up>
+ constexpr indirect&
+ operator=(_Up&& __u)
+ {
+ if (_M_objp == nullptr)
+ _M_objp = _M_make_obj(std::forward<_Up>(__u));
+ else
+ *_M_objp = std::forward<_Up>(__u);
+
+ return *this;
+ }
+
+ template<typename _Self>
+ constexpr auto&&
+ operator*(this _Self&& __self) noexcept
+ {
+ __glibcxx_assert(__self._M_objp != nullptr);
+ return std::forward_like<_Self>(*((_Self)__self)._M_objp);
+ }
+
+ constexpr const_pointer
+ operator->() const noexcept
+ {
+ // Do we want to enforce this? __glibcxx_assert(_M_objp != nullptr);
+ return _M_objp;
+ }
+
+ constexpr pointer
+ operator->() noexcept
+ {
+ // Do we want to enforce this? __glibcxx_assert(_M_objp != nullptr);
+ return _M_objp;
+ }
+
+ constexpr bool
+ valueless_after_move() const noexcept { return _M_objp == nullptr; }
+
+ constexpr allocator_type
+ get_allocator() const noexcept { return _M_alloc; }
+
+ constexpr void
+ swap(indirect& __other)
+ noexcept(_ATraits::propagate_on_container_swap::value
+ || _ATraits::is_always_equal::value)
+ {
+ using std::swap;
+ swap(_M_objp, __other._M_objp);
+ if constexpr (_ATraits::propagate_on_container_swap::value)
+ swap(_M_alloc, __other._M_alloc);
+ else if constexpr (!_ATraits::is_always_equal::value)
+ __glibcxx_assert(_M_alloc == __other._M_alloc);
+ }
+
+ friend constexpr void
+ swap(indirect& __lhs, indirect& __rhs)
+ noexcept(_ATraits::propagate_on_container_swap::value
+ || _ATraits::is_always_equal::value)
+ { __lhs.swap(__rhs); }
+
+ template<typename _Up, typename _Alloc2>
+ requires requires (const _Tp& __t, const _Up& __u) { __t == __u; }
+ friend constexpr bool
+ operator==(const indirect& __lhs, const indirect<_Up, _Alloc2>& __rhs)
+ noexcept(noexcept(*__lhs == *__rhs))
+ {
+ if (!__lhs._M_objp || !__rhs._M_objp)
+ return bool(__lhs._M_objp) == bool(__rhs._M_objp);
+ else
+ return __lhs.__get() == __rhs.__get();
+ }
+
+ template<typename _Up>
+ requires (!__is_indirect<_Up>) // See PR c++/99599
+ && requires (const _Tp& __t, const _Up& __u) { __t == __u; }
+ friend constexpr bool
+ operator==(const indirect& __lhs, const _Up& __rhs)
+ noexcept(noexcept(*__lhs == __rhs))
+ {
+ if (!__lhs._M_objp)
+ return false;
+ else
+ return __lhs.__get() == __rhs;
+ }
+
+ template<typename _Up, typename _Alloc2>
+ friend constexpr __detail::__synth3way_t<_Tp, _Up>
+ operator<=>(const indirect& __lhs, const indirect<_Up, _Alloc2>& __rhs)
+ noexcept(noexcept(__detail::__synth3way(*__lhs, *__rhs)))
+ {
+ if (!__lhs._M_objp || !__rhs._M_objp)
+ return bool(__lhs._M_objp) <=> bool(__rhs._M_objp);
+ else
+ return __detail::__synth3way(__lhs.__get(), __rhs.__get());
+ }
+
+ template<typename _Up>
+ requires (!__is_indirect<_Up>) // See PR c++/99599
+ friend constexpr __detail::__synth3way_t<_Tp, _Up>
+ operator<=>(const indirect& __lhs, const _Up& __rhs)
+ noexcept(noexcept(__detail::__synth3way(*__lhs, __rhs)))
+ {
+ if (!__lhs._M_objp)
+ return strong_ordering::less;
+ else
+ return __detail::__synth3way(__lhs.__get(), __rhs);
+ }
+
+ private:
+ template<typename, typename> friend class indirect;
+
+ constexpr void
+ _M_reset(pointer __ptr) noexcept
+ {
+ if (_M_objp)
+ {
+ _ATraits::destroy(_M_alloc, std::to_address(_M_objp));
+ _ATraits::deallocate(_M_alloc, _M_objp, 1);
+ }
+ _M_objp = __ptr;
+ }
+
+ template<typename... _Args>
+ constexpr pointer
+ _M_make_obj(_Args&&... __args) const
+ {
+ _Scoped_allocation __sa(_M_alloc, in_place,
+ std::forward<_Args>(__args)...);
+ return __sa.release();
+ }
+
+ // Enforces is_constructible check and then calls _M_make_obj.
+ template<typename... _Args>
+ [[__gnu__::__always_inline__]]
+ constexpr pointer
+ _M_make_obj_chk(_Args&&... __args) const
+ {
+ static_assert(is_constructible_v<_Tp, _Args...>);
+ return _M_make_obj(std::forward<_Args>(__args)...);
+ }
+
+ // Always-const accessor that avoids ADL for operator*.
+ // This can be preferable to using *_M_objp because that might give _Tp&.
+ // This can be preferable to using **this because that does ADL.
+ [[__gnu__::__always_inline__]]
+ constexpr const _Tp&
+ __get() const noexcept
+ { return *_M_objp; }
+
+ [[no_unique_address]] _Alloc _M_alloc = _Alloc();
+ pointer _M_objp; // Pointer to the owned object.
+ };
+
+ template<typename _Value>
+ indirect(_Value) -> indirect<_Value>;
+
+ template<typename _Alloc, typename _Value>
+ indirect(allocator_arg_t, _Alloc, _Value)
+ -> indirect<_Value, __alloc_rebind<_Alloc, _Value>>;
+
+ // [indirect.hash], hash support
+ template<typename _Tp, typename _Alloc>
+ requires is_default_constructible_v<hash<_Tp>>
+ struct hash<indirect<_Tp, _Alloc>>
+ {
+ constexpr size_t
+ operator()(const indirect<_Tp, _Alloc>& __t) const
+ noexcept(noexcept(hash<_Tp>{}(*__t)))
+ {
+ // We pick an arbitrary hash for valueless indirect objects
+ // which hopefully usual values of _Tp won't typically hash to.
+ if (__t.valueless_after_move())
+ return -4444zu;
+ return hash<_Tp>{}(*__t);
+ }
+ };
+
+ template<typename _Tp, typename _Alloc>
+ struct __is_fast_hash<hash<indirect<_Tp, _Alloc>>>
+ : __is_fast_hash<hash<_Tp>>
+ { };
+#endif // __glibcxx_indirect
+
+#if __glibcxx_polymorphic // C++26 && HOSTED
+ template<typename _Tp, typename _Alloc = allocator<_Tp>>
+ class polymorphic;
+
+ namespace pmr
+ {
+ template<typename _Tp>
+ using polymorphic = polymorphic<_Tp, polymorphic_allocator<_Tp>>;
+ }
+
+ // [polymorphic], class template polymorphic
+ template<typename _Tp, typename _Alloc>
+ class polymorphic
+ {
+ static_assert(is_object_v<_Tp>);
+ static_assert(!is_array_v<_Tp>);
+ static_assert(!is_same_v<_Tp, in_place_t>);
+ static_assert(!__is_in_place_type_v<_Tp>);
+ static_assert(!is_const_v<_Tp> && !is_volatile_v<_Tp>);
+
+ using _ATraits = allocator_traits<_Alloc>;
+ static_assert(is_same_v<_Tp, typename _ATraits::value_type>);
+
+ // The owned object is embedded within a control block which knows the
+ // dynamic type and manages cloning and destroying the owned object.
+ struct _Obj
+ {
+ typename _ATraits::pointer _M_objp{}; // pointer to the owned object.
+
+ // A pointer to this type, e.g. _Obj*
+ using pointer
+ = typename _ATraits::template rebind_traits<_Obj>::pointer;
+
+ enum class _Op { _Dispose = 1, _Copy = 2, _Move = 3 };
+
+ constexpr virtual pointer
+ _M_manage(const _Alloc&, _Op, void* = nullptr) = 0;
+ };
+
+ template<typename _Up>
+ struct _Obj_impl : _Obj
+ {
+ using _MyTraits
+ = typename _ATraits::template rebind_traits<_Obj_impl>;
+
+ using _Op = _Obj::_Op;
+
+ union _Uninitialized {
+ constexpr _Uninitialized() { }
+ constexpr ~_Uninitialized() { }
+ _Up _M_objp;
+ };
+ _Uninitialized _M_u;
+
+ template<typename... _Args>
+ constexpr
+ _Obj_impl(typename _MyTraits::allocator_type& __a,
+ _Args&&... __args)
+ {
+ using _PtrTr = pointer_traits<typename _ATraits::pointer>;
+ _MyTraits::construct(__a, __builtin_addressof(_M_u._M_objp),
+ std::forward<_Args>(__args)...);
+ this->_M_objp = _PtrTr::pointer_to(_M_u._M_objp);
+ }
+
+ constexpr virtual typename _Obj::pointer
+ _M_manage(const _Alloc& __a, _Op __op, void*) override
+ {
+
+ switch (__op)
+ {
+ case _Op::_Move:
+ return _S_make_obj<_Up>(__a, std::move(_M_u._M_objp));
+ case _Op::_Copy:
+ return _S_make_obj<_Up>(__a,
+ const_cast<const _Up&>(_M_u._M_objp));
+ case _Op::_Dispose:
+ {
+ using _PtrTr = pointer_traits<typename _MyTraits::pointer>;
+ typename _MyTraits::allocator_type __a2(__a);
+ _MyTraits::destroy(__a2, std::__addressof(_M_u._M_objp));
+ _MyTraits::deallocate(__a2, _PtrTr::pointer_to(*this), 1);
+ return nullptr;
+ }
+ }
+ __builtin_unreachable();
+ }
+ };
+
+ // TODO: the standard permits a small-object optimization where the
+ // owned object is nested within the std::polymorphic not on the heap.
+
+ public:
+
+ using value_type = _Tp;
+ using allocator_type = _Alloc;
+ using pointer = typename allocator_traits<_Alloc>::pointer;
+ using const_pointer = typename allocator_traits<_Alloc>::const_pointer;
+
+ constexpr explicit
+ polymorphic() requires is_default_constructible_v<_Alloc>
+ : polymorphic(in_place_type<_Tp>)
+ { }
+
+ constexpr explicit
+ polymorphic(allocator_arg_t, const _Alloc& __a)
+ : polymorphic(allocator_arg, __a, in_place_type<_Tp>)
+ { }
+
+ constexpr
+ polymorphic(const polymorphic& __other)
+ : polymorphic(allocator_arg,
+ _ATraits::select_on_container_copy_construction(
+ __other._M_alloc),
+ __other)
+ { }
+
+ constexpr
+ polymorphic(allocator_arg_t, const _Alloc& __a,
+ const polymorphic& __other)
+ : _M_alloc(__a)
+ {
+ if (__other._M_objp)
+ _M_objp = __other._M_objp->_M_manage(__a, _Obj::_Op::_Copy);
+ else
+ _M_objp = nullptr;
+ }
+
+ constexpr
+ polymorphic(polymorphic&& __other) noexcept
+ : _M_alloc(std::move(__other._M_alloc)),
+ _M_objp(std::__exchange(__other._M_objp, nullptr))
+ { }
+
+ constexpr
+ polymorphic(allocator_arg_t, const _Alloc& __a, polymorphic&& __other)
+ noexcept(_ATraits::is_always_equal::value)
+ : _M_alloc(__a),
+ _M_objp(std::__exchange(__other._M_objp, nullptr))
+ {
+ if constexpr (!_ATraits::is_always_equal::value)
+ if (_M_objp && _M_alloc != __other._M_alloc)
+ {
+ // _M_alloc cannot free _M_objp, give it back to __other.
+ __other._M_objp = std::__exchange(_M_objp, nullptr);
+ // And create a new object that can be freed by _M_alloc.
+ _M_objp = __other._M_objp->_M_manage(__a, _Obj::_Op::_Move);
+ }
+ }
+
+ template<typename _Up = _Tp, typename _UUp = remove_cvref_t<_Up>>
+ requires (!is_same_v<_UUp, polymorphic>)
+ && (!__is_in_place_type_v<_UUp>)
+ && derived_from<_UUp, _Tp>
+ && is_constructible_v<_UUp, _Up>
+ && is_copy_constructible_v<_UUp>
+ && is_default_constructible_v<_Alloc>
+ constexpr explicit
+ polymorphic(_Up&& __u)
+ : _M_objp(_M_make_obj<_UUp>(std::forward<_Up>(__u)))
+ { }
+
+ template<typename _Up = _Tp, typename _UUp = remove_cvref_t<_Up>>
+ requires (!is_same_v<_UUp, polymorphic>)
+ && (!__is_in_place_type_v<_UUp>)
+ && derived_from<_UUp, _Tp>
+ && is_constructible_v<_UUp, _Up>
+ && is_copy_constructible_v<_UUp>
+ constexpr explicit
+ polymorphic(allocator_arg_t, const _Alloc& __a, _Up&& __u)
+ : _M_alloc(__a), _M_objp(_M_make_obj<_UUp>(std::forward<_Up>(__u)))
+ { }
+
+ template<typename _Up, typename... _Ts>
+ requires is_same_v<remove_cvref_t<_Up>, _Up>
+ && derived_from<_Up, _Tp>
+ && is_constructible_v<_Up, _Ts...>
+ && is_copy_constructible_v<_Up>
+ && is_default_constructible_v<_Alloc>
+ constexpr explicit
+ polymorphic(in_place_type_t<_Up> __t, _Ts&&... __ts)
+ : _M_objp(_M_make_obj<_Up>(std::forward<_Ts>(__ts)...))
+ { }
+
+ template<typename _Up, typename... _Ts>
+ requires is_same_v<remove_cvref_t<_Up>, _Up>
+ && derived_from<_Up, _Tp>
+ && is_constructible_v<_Up, _Ts...>
+ && is_copy_constructible_v<_Up>
+ constexpr explicit
+ polymorphic(allocator_arg_t, const _Alloc& __a,
+ in_place_type_t<_Up>, _Ts&&... __ts)
+ : _M_alloc(__a),
+ _M_objp(_M_make_obj<_Up>(std::forward<_Ts>(__ts)...))
+ { }
+
+ template<typename _Up, typename _Ip, typename... _Us>
+ requires is_same_v<remove_cvref_t<_Up>, _Up>
+ && derived_from<_Up, _Tp>
+ && is_constructible_v<_Up, initializer_list<_Ip>&, _Us...>
+ && is_copy_constructible_v<_Up>
+ && is_default_constructible_v<_Alloc>
+ constexpr explicit
+ polymorphic(in_place_type_t<_Up>, initializer_list<_Ip> __il,
+ _Us&&... __us)
+ : _M_objp(_M_make_obj<_Up>(__il, std::forward<_Us>(__us)...))
+ { }
+
+ template<typename _Up, typename _Ip, typename... _Us>
+ requires is_same_v<remove_cvref_t<_Up>, _Up>
+ && derived_from<_Up, _Tp>
+ && is_constructible_v<_Up, initializer_list<_Ip>&, _Us...>
+ && is_copy_constructible_v<_Up>
+ constexpr explicit
+ polymorphic(allocator_arg_t, const _Alloc& __a,
+ in_place_type_t<_Up>, initializer_list<_Ip> __il,
+ _Us&&... __us)
+ : _M_alloc(__a),
+ _M_objp(_M_make_obj<_Up>(__il, std::forward<_Us>(__us)...))
+ { }
+
+ constexpr ~polymorphic()
+ {
+ static_assert(sizeof(_Tp) != 0, "must be a complete type");
+ _M_reset(nullptr);
+ }
+
+ constexpr polymorphic&
+ operator=(const polymorphic& __other)
+ {
+ static_assert(sizeof(_Tp) != 0, "must be a complete type");
+
+ if (__builtin_addressof(__other) == this) [[unlikely]]
+ return *this;
+
+ constexpr bool __pocca
+ = _ATraits::propagate_on_container_copy_assignment::value;
+
+ typename _Obj::pointer __ptr = nullptr;
+ if (__other._M_objp)
+ {
+ auto& __a = __pocca ? __other._M_alloc : _M_alloc;
+ __ptr = __other._M_objp->_M_manage(__a, _Obj::_Op::_Copy);
+ }
+
+ _M_reset(__ptr);
+
+ if constexpr (__pocca)
+ _M_alloc = __other._M_alloc;
+
+ return *this;
+ }
+
+ constexpr polymorphic&
+ operator=(polymorphic&& __other)
+ noexcept(_ATraits::propagate_on_container_move_assignment::value
+ || _ATraits::is_always_equal::value)
+ {
+ if (__builtin_addressof(__other) == this) [[unlikely]]
+ return *this;
+
+ constexpr bool __pocma
+ = _ATraits::propagate_on_container_move_assignment::value;
+
+ typename _Obj::pointer __ptr = nullptr;
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4251. Move assignment for indirect unnecessarily requires copy construction
+ if constexpr (_ATraits::is_always_equal::value || __pocma)
+ __ptr = std::__exchange(__other._M_objp, nullptr);
+ else if (_M_alloc == __other._M_alloc)
+ __ptr = std::__exchange(__other._M_objp, nullptr);
+ else if (__other._M_objp)
+ {
+ static_assert(sizeof(_Tp) != 0, "must be a complete type");
+ __ptr = __other._M_objp->_M_manage(_M_alloc, _Obj::_Op::_Move);
+ }
+
+ _M_reset(__ptr);
+
+ if constexpr (__pocma)
+ _M_alloc = __other._M_alloc;
+
+ return *this;
+ }
+
+ constexpr const _Tp&
+ operator*() const noexcept
+ {
+ __glibcxx_assert(_M_objp != nullptr);
+ return *_M_objp->_M_objp;
+ }
+
+ constexpr _Tp&
+ operator*() noexcept
+ {
+ __glibcxx_assert(_M_objp != nullptr);
+ return *_M_objp->_M_objp;
+ }
+
+ constexpr const_pointer
+ operator->() const noexcept
+ {
+ __glibcxx_assert(_M_objp != nullptr);
+ return _M_objp ? _M_objp->_M_objp : const_pointer{};
+ }
+
+ constexpr pointer
+ operator->() noexcept
+ {
+ __glibcxx_assert(_M_objp != nullptr);
+ return _M_objp ? _M_objp->_M_objp : pointer{};
+ }
+
+ constexpr bool
+ valueless_after_move() const noexcept { return _M_objp == nullptr; }
+
+ constexpr allocator_type
+ get_allocator() const noexcept { return _M_alloc; }
+
+ constexpr void
+ swap(polymorphic& __other)
+ noexcept(_ATraits::propagate_on_container_swap::value
+ || _ATraits::is_always_equal::value)
+ {
+ using std::swap;
+ swap(_M_objp, __other._M_objp);
+ if constexpr (_ATraits::propagate_on_container_swap::value)
+ swap(_M_alloc, __other._M_alloc);
+ else if constexpr (!_ATraits::is_always_equal::value)
+ __glibcxx_assert(_M_alloc == __other._M_alloc);
+ }
+
+ friend constexpr void
+ swap(polymorphic& __lhs, polymorphic& __rhs)
+ noexcept(_ATraits::propagate_on_container_swap::value
+ || _ATraits::is_always_equal::value)
+ { __lhs.swap(__rhs); }
+
+ private:
+ template<typename _Up, typename... _Args>
+ static constexpr typename _Obj::pointer
+ _S_make_obj(const _Alloc& __a, _Args&&... __args)
+ {
+ __alloc_rebind<_Alloc, _Obj_impl<_Up>> __objalloc(__a);
+ _Scoped_allocation __sa(__objalloc, in_place, __objalloc,
+ std::forward<_Args>(__args)...);
+ auto __obj = __sa.release();
+ // FIXME: We need to downcast from _Obj_impl<U>* to _Obj* but the
+ // the pointer_traits usage breaks in constexpr. PR c++/110714
+ if constexpr (is_pointer_v<typename _Obj::pointer>)
+ return __obj;
+ else
+ return pointer_traits<typename _Obj::pointer>::pointer_to(*__obj);
+ }
+
+ template<typename _Up, typename... _Args>
+ constexpr typename _Obj::pointer
+ _M_make_obj(_Args&&... __args) const
+ { return _S_make_obj<_Up>(_M_alloc, std::forward<_Args>(__args)...); }
+
+ constexpr void
+ _M_reset(typename _Obj::pointer __ptr) noexcept
+ {
+ if (_M_objp)
+ _M_objp->_M_manage(_M_alloc, _Obj::_Op::_Dispose);
+ _M_objp = __ptr;
+ }
+
+ [[no_unique_address]] _Alloc _M_alloc = _Alloc();
+ typename _Obj::pointer _M_objp;
+ };
+#endif // __glibcxx_polymorphic
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+#endif // C++26 __glibcxx_indirect || __glibcxx_polymorphic
+
+#endif // _GLIBCXX_INDIRECT_H
diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h
index 3b73ff9..d31e4f1 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -1022,19 +1022,10 @@ namespace ranges
{
using std::__detail::__class_or_enum;
- struct _Decay_copy final
- {
- template<typename _Tp>
- constexpr decay_t<_Tp>
- operator()(_Tp&& __t) const
- noexcept(is_nothrow_convertible_v<_Tp, decay_t<_Tp>>)
- { return std::forward<_Tp>(__t); }
- } inline constexpr __decay_copy{};
-
template<typename _Tp>
concept __member_begin = requires(_Tp& __t)
{
- { __decay_copy(__t.begin()) } -> input_or_output_iterator;
+ { _GLIBCXX_AUTO_CAST(__t.begin()) } -> input_or_output_iterator;
};
// Poison pill so that unqualified lookup doesn't find std::begin.
@@ -1044,7 +1035,7 @@ namespace ranges
concept __adl_begin = __class_or_enum<remove_reference_t<_Tp>>
&& requires(_Tp& __t)
{
- { __decay_copy(begin(__t)) } -> input_or_output_iterator;
+ { _GLIBCXX_AUTO_CAST(begin(__t)) } -> input_or_output_iterator;
};
// Simplified version of std::ranges::begin that only supports lvalues,
diff --git a/libstdc++-v3/include/bits/max_size_type.h b/libstdc++-v3/include/bits/max_size_type.h
index 5bec0b5..73a6d14 100644
--- a/libstdc++-v3/include/bits/max_size_type.h
+++ b/libstdc++-v3/include/bits/max_size_type.h
@@ -36,6 +36,7 @@
#if __cplusplus > 201703L && __cpp_lib_concepts
#include <ext/numeric_traits.h>
+#include <bit> // __bit_width
#include <numbers>
// This header implements unsigned and signed integer-class types (as per
@@ -425,10 +426,11 @@ namespace ranges
using __rep = unsigned long long;
#endif
static constexpr size_t _S_rep_bits = sizeof(__rep) * __CHAR_BIT__;
- private:
+
__rep _M_val = 0;
unsigned _M_msb:1 = 0;
+ private:
constexpr explicit
__max_size_type(__rep __val, int __msb) noexcept
: _M_val(__val), _M_msb(__msb)
@@ -752,7 +754,6 @@ namespace ranges
{ return !(__l < __r); }
#endif
- private:
__max_size_type _M_rep = 0;
friend class __max_size_type;
@@ -818,6 +819,16 @@ namespace ranges
{ return min(); }
};
+ template<>
+ inline constexpr int
+ __bit_width(ranges::__detail::__max_size_type __x) noexcept
+ {
+ if (__x._M_msb)
+ return numeric_limits<ranges::__detail::__max_size_type>::digits;
+ else
+ return std::__bit_width(__x._M_val);
+ }
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
diff --git a/libstdc++-v3/include/bits/mofunc_impl.h b/libstdc++-v3/include/bits/mofunc_impl.h
index 318a55e..468e685 100644
--- a/libstdc++-v3/include/bits/mofunc_impl.h
+++ b/libstdc++-v3/include/bits/mofunc_impl.h
@@ -62,8 +62,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Res, typename... _ArgTypes, bool _Noex>
class move_only_function<_Res(_ArgTypes...) _GLIBCXX_MOF_CV
_GLIBCXX_MOF_REF noexcept(_Noex)>
- : _Mofunc_base
+ : __polyfunc::_Mo_base
{
+ static_assert(
+ (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>()) && ...),
+ "each parameter type must be a complete class");
+
+ using _Base = __polyfunc::_Mo_base;
+ using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>;
+ using _Signature = _Invoker::_Signature;
+
template<typename _Tp>
using __callable
= __conditional_t<_Noex,
@@ -87,7 +95,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Moves the target object, leaving the source empty.
move_only_function(move_only_function&& __x) noexcept
- : _Mofunc_base(static_cast<_Mofunc_base&&>(__x)),
+ : _Base(static_cast<_Base&&>(__x)),
_M_invoke(std::__exchange(__x._M_invoke, nullptr))
{ }
@@ -97,15 +105,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
&& (!__is_in_place_type_v<_Vt>) && __is_callable_from<_Vt>
move_only_function(_Fn&& __f) noexcept(_S_nothrow_init<_Vt, _Fn>())
{
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4255. move_only_function constructor should recognize empty
+ // copyable_functions
if constexpr (is_function_v<remove_pointer_t<_Vt>>
|| is_member_pointer_v<_Vt>
- || __is_move_only_function_v<_Vt>)
+ || __is_polymorphic_function_v<_Vt>)
{
if (__f == nullptr)
return;
}
- _M_init<_Vt>(std::forward<_Fn>(__f));
- _M_invoke = &_S_invoke<_Vt>;
+
+ if constexpr (__is_polymorphic_function_v<_Vt>
+ && __polyfunc::__is_invoker_convertible<_Vt, move_only_function>())
+ {
+ // Handle cases where _Fn is const reference to copyable_function,
+ // by firstly creating temporary and moving from it.
+ _Vt __tmp(std::forward<_Fn>(__f));
+ _M_move(__polyfunc::__base_of(__tmp));
+ _M_invoke = std::__exchange(__polyfunc::__invoker_of(__tmp), nullptr);
+ }
+ else
+ {
+ _M_init<_Vt>(std::forward<_Fn>(__f));
+ _M_invoke = _Invoker::template _S_storage<_Vt _GLIBCXX_MOF_INV_QUALS>();
+ }
}
/// Stores a target object initialized from the arguments.
@@ -115,7 +139,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
explicit
move_only_function(in_place_type_t<_Tp>, _Args&&... __args)
noexcept(_S_nothrow_init<_Tp, _Args...>())
- : _M_invoke(&_S_invoke<_Tp>)
+ : _M_invoke(_Invoker::template _S_storage<_Tp _GLIBCXX_MOF_INV_QUALS>())
{
static_assert(is_same_v<decay_t<_Tp>, _Tp>);
_M_init<_Tp>(std::forward<_Args>(__args)...);
@@ -129,7 +153,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
move_only_function(in_place_type_t<_Tp>, initializer_list<_Up> __il,
_Args&&... __args)
noexcept(_S_nothrow_init<_Tp, initializer_list<_Up>&, _Args...>())
- : _M_invoke(&_S_invoke<_Tp>)
+ : _M_invoke(_Invoker::template _S_storage<_Tp _GLIBCXX_MOF_INV_QUALS>())
{
static_assert(is_same_v<decay_t<_Tp>, _Tp>);
_M_init<_Tp>(__il, std::forward<_Args>(__args)...);
@@ -139,8 +163,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
move_only_function&
operator=(move_only_function&& __x) noexcept
{
- _Mofunc_base::operator=(static_cast<_Mofunc_base&&>(__x));
- _M_invoke = std::__exchange(__x._M_invoke, nullptr);
+ // Standard requires support of self assigment, by specifying it as
+ // copy and swap.
+ if (this != std::addressof(__x)) [[likely]]
+ {
+ _Base::operator=(static_cast<_Base&&>(__x));
+ _M_invoke = std::__exchange(__x._M_invoke, nullptr);
+ }
return *this;
}
@@ -148,7 +177,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
move_only_function&
operator=(nullptr_t) noexcept
{
- _Mofunc_base::operator=(nullptr);
+ _M_reset();
_M_invoke = nullptr;
return *this;
}
@@ -167,7 +196,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
~move_only_function() = default;
/// True if a target object is present, false otherwise.
- explicit operator bool() const noexcept { return _M_invoke != nullptr; }
+ explicit operator bool() const noexcept
+ { return _M_invoke != nullptr; }
/** Invoke the target object.
*
@@ -181,14 +211,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator()(_ArgTypes... __args) _GLIBCXX_MOF_CV_REF noexcept(_Noex)
{
__glibcxx_assert(*this != nullptr);
- return _M_invoke(this, std::forward<_ArgTypes>(__args)...);
+ return _M_invoke(this->_M_storage, std::forward<_ArgTypes>(__args)...);
}
/// Exchange the target objects (if any).
void
swap(move_only_function& __x) noexcept
{
- _Mofunc_base::swap(__x);
+ _Base::swap(__x);
std::swap(_M_invoke, __x._M_invoke);
}
@@ -203,25 +233,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __x._M_invoke == nullptr; }
private:
- template<typename _Tp>
- using __param_t = __conditional_t<is_scalar_v<_Tp>, _Tp, _Tp&&>;
+ typename _Invoker::__storage_func_t _M_invoke = nullptr;
- using _Invoker = _Res (*)(_Mofunc_base _GLIBCXX_MOF_CV*,
- __param_t<_ArgTypes>...) noexcept(_Noex);
+ template<typename _Func>
+ friend auto&
+ __polyfunc::__invoker_of(_Func&) noexcept;
- template<typename _Tp>
- static _Res
- _S_invoke(_Mofunc_base _GLIBCXX_MOF_CV* __self,
- __param_t<_ArgTypes>... __args) noexcept(_Noex)
- {
- using _TpCv = _Tp _GLIBCXX_MOF_CV;
- using _TpInv = _Tp _GLIBCXX_MOF_INV_QUALS;
- return std::__invoke_r<_Res>(
- std::forward<_TpInv>(*_S_access<_TpCv>(__self)),
- std::forward<__param_t<_ArgTypes>>(__args)...);
- }
+ template<typename _Func>
+ friend auto&
+ __polyfunc::__base_of(_Func&) noexcept;
- _Invoker _M_invoke = nullptr;
+ template<typename _Dst, typename _Src>
+ friend consteval bool
+ __polyfunc::__is_invoker_convertible() noexcept;
};
#undef _GLIBCXX_MOF_CV_REF
diff --git a/libstdc++-v3/include/bits/move_only_function.h b/libstdc++-v3/include/bits/move_only_function.h
deleted file mode 100644
index 42b33d0..0000000
--- a/libstdc++-v3/include/bits/move_only_function.h
+++ /dev/null
@@ -1,218 +0,0 @@
-// Implementation of std::move_only_function -*- 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/bits/move_only_function.h
- * This is an internal header file, included by other library headers.
- * Do not attempt to use it directly. @headername{functional}
- */
-
-#ifndef _GLIBCXX_MOVE_ONLY_FUNCTION_H
-#define _GLIBCXX_MOVE_ONLY_FUNCTION_H 1
-
-#ifdef _GLIBCXX_SYSHDR
-#pragma GCC system_header
-#endif
-
-#include <bits/version.h>
-
-#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
-
-#include <bits/invoke.h>
-#include <bits/utility.h>
-
-namespace std _GLIBCXX_VISIBILITY(default)
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
- template<typename... _Signature>
- class move_only_function; // not defined
-
- /// @cond undocumented
- class _Mofunc_base
- {
- protected:
- _Mofunc_base() noexcept
- : _M_manage(_S_empty)
- { }
-
- _Mofunc_base(_Mofunc_base&& __x) noexcept
- {
- _M_manage = std::__exchange(__x._M_manage, _S_empty);
- _M_manage(_M_storage, &__x._M_storage);
- }
-
- template<typename _Tp, typename... _Args>
- static constexpr bool
- _S_nothrow_init() noexcept
- {
- if constexpr (__stored_locally<_Tp>)
- return is_nothrow_constructible_v<_Tp, _Args...>;
- return false;
- }
-
- template<typename _Tp, typename... _Args>
- void
- _M_init(_Args&&... __args) noexcept(_S_nothrow_init<_Tp, _Args...>())
- {
- if constexpr (__stored_locally<_Tp>)
- ::new (_M_storage._M_addr()) _Tp(std::forward<_Args>(__args)...);
- else
- _M_storage._M_p = new _Tp(std::forward<_Args>(__args)...);
-
- _M_manage = &_S_manage<_Tp>;
- }
-
- _Mofunc_base&
- operator=(_Mofunc_base&& __x) noexcept
- {
- _M_manage(_M_storage, nullptr);
- _M_manage = std::__exchange(__x._M_manage, _S_empty);
- _M_manage(_M_storage, &__x._M_storage);
- return *this;
- }
-
- _Mofunc_base&
- operator=(nullptr_t) noexcept
- {
- _M_manage(_M_storage, nullptr);
- _M_manage = _S_empty;
- return *this;
- }
-
- ~_Mofunc_base() { _M_manage(_M_storage, nullptr); }
-
- void
- swap(_Mofunc_base& __x) noexcept
- {
- // Order of operations here is more efficient if __x is empty.
- _Storage __s;
- __x._M_manage(__s, &__x._M_storage);
- _M_manage(__x._M_storage, &_M_storage);
- __x._M_manage(_M_storage, &__s);
- std::swap(_M_manage, __x._M_manage);
- }
-
- template<typename _Tp, typename _Self>
- static _Tp*
- _S_access(_Self* __self) noexcept
- {
- if constexpr (__stored_locally<remove_const_t<_Tp>>)
- return static_cast<_Tp*>(__self->_M_storage._M_addr());
- else
- return static_cast<_Tp*>(__self->_M_storage._M_p);
- }
-
- private:
- struct _Storage
- {
- void* _M_addr() noexcept { return &_M_bytes[0]; }
- const void* _M_addr() const noexcept { return &_M_bytes[0]; }
-
- // We want to have enough space to store a simple delegate type.
- struct _Delegate { void (_Storage::*__pfm)(); _Storage* __obj; };
- union {
- void* _M_p;
- alignas(_Delegate) alignas(void(*)())
- unsigned char _M_bytes[sizeof(_Delegate)];
- };
- };
-
- template<typename _Tp>
- static constexpr bool __stored_locally
- = sizeof(_Tp) <= sizeof(_Storage) && alignof(_Tp) <= alignof(_Storage)
- && is_nothrow_move_constructible_v<_Tp>;
-
- // A function that either destroys the target object stored in __target,
- // or moves the target object from *__src to __target.
- using _Manager = void (*)(_Storage& __target, _Storage* __src) noexcept;
-
- // The no-op manager function for objects with no target.
- static void _S_empty(_Storage&, _Storage*) noexcept { }
-
- // The real manager function for a target object of type _Tp.
- template<typename _Tp>
- static void
- _S_manage(_Storage& __target, _Storage* __src) noexcept
- {
- if constexpr (__stored_locally<_Tp>)
- {
- if (__src)
- {
- _Tp* __rval = static_cast<_Tp*>(__src->_M_addr());
- ::new (__target._M_addr()) _Tp(std::move(*__rval));
- __rval->~_Tp();
- }
- else
- static_cast<_Tp*>(__target._M_addr())->~_Tp();
- }
- else
- {
- if (__src)
- __target._M_p = __src->_M_p;
- else
- delete static_cast<_Tp*>(__target._M_p);
- }
- }
-
- _Storage _M_storage;
- _Manager _M_manage;
- };
-
- template<typename _Tp>
- inline constexpr bool __is_move_only_function_v = false;
- template<typename _Tp>
- constexpr bool __is_move_only_function_v<move_only_function<_Tp>> = true;
- /// @endcond
-
- namespace __detail::__variant
- {
- template<typename> struct _Never_valueless_alt; // see <variant>
-
- // Provide the strong exception-safety guarantee when emplacing a
- // move_only_function into a variant.
- template<typename... _Signature>
- struct _Never_valueless_alt<std::move_only_function<_Signature...>>
- : true_type
- { };
- } // namespace __detail::__variant
-
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace std
-
-#include "mofunc_impl.h"
-#define _GLIBCXX_MOF_CV const
-#include "mofunc_impl.h"
-#define _GLIBCXX_MOF_REF &
-#include "mofunc_impl.h"
-#define _GLIBCXX_MOF_REF &&
-#include "mofunc_impl.h"
-#define _GLIBCXX_MOF_CV const
-#define _GLIBCXX_MOF_REF &
-#include "mofunc_impl.h"
-#define _GLIBCXX_MOF_CV const
-#define _GLIBCXX_MOF_REF &&
-#include "mofunc_impl.h"
-
-#endif // __glibcxx_move_only_function
-#endif // _GLIBCXX_MOVE_ONLY_FUNCTION_H
diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h
index 4308669..91da88b 100644
--- a/libstdc++-v3/include/bits/ptr_traits.h
+++ b/libstdc++-v3/include/bits/ptr_traits.h
@@ -36,7 +36,7 @@
#if __cplusplus > 201703L
#include <concepts>
-namespace __gnu_debug { struct _Safe_iterator_base; }
+namespace __gnu_debug { class _Safe_iterator_base; }
#endif
namespace std _GLIBCXX_VISIBILITY(default)
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index f36e7dd..cf369c5 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -32,6 +32,7 @@
#if __cplusplus > 201703L
+#include <bit> // __bit_width
#if __cplusplus > 202002L
#include <optional>
#endif
@@ -47,28 +48,60 @@ namespace ranges
{
namespace __detail
{
+ template<typename _Fp>
+ using __by_ref_or_value_fn
+ = __conditional_t<is_scalar_v<_Fp> || is_empty_v<_Fp>, _Fp, _Fp&>;
+
template<typename _Comp, typename _Proj>
- constexpr auto
+ struct _Comp_proj
+ {
+ [[no_unique_address]] __by_ref_or_value_fn<_Comp> _M_comp;
+ [[no_unique_address]] __by_ref_or_value_fn<_Proj> _M_proj;
+
+ constexpr
+ _Comp_proj(_Comp& __comp, _Proj& __proj)
+ : _M_comp(__comp), _M_proj(__proj)
+ { }
+
+ template<typename _Tp, typename _Up>
+ constexpr bool
+ operator()(_Tp&& __x, _Up&& __y)
+ {
+ return std::__invoke(_M_comp,
+ std::__invoke(_M_proj, std::forward<_Tp>(__x)),
+ std::__invoke(_M_proj, std::forward<_Up>(__y)));
+ }
+ };
+
+ template<typename _Comp, typename _Proj>
+ constexpr _Comp_proj<_Comp, _Proj>
__make_comp_proj(_Comp& __comp, _Proj& __proj)
+ { return {__comp, __proj}; }
+
+ template<typename _Pred, typename _Proj>
+ struct _Pred_proj
{
- return [&] (auto&& __lhs, auto&& __rhs) -> bool {
- using _TL = decltype(__lhs);
- using _TR = decltype(__rhs);
- return std::__invoke(__comp,
- std::__invoke(__proj, std::forward<_TL>(__lhs)),
- std::__invoke(__proj, std::forward<_TR>(__rhs)));
- };
- }
+ [[no_unique_address]] __by_ref_or_value_fn<_Pred> _M_pred;
+ [[no_unique_address]] __by_ref_or_value_fn<_Proj> _M_proj;
+
+ constexpr
+ _Pred_proj(_Pred& __pred, _Proj& __proj)
+ : _M_pred(__pred), _M_proj(__proj)
+ { }
+
+ template<typename _Tp>
+ constexpr bool
+ operator()(_Tp&& __x)
+ {
+ return std::__invoke(_M_pred,
+ std::__invoke(_M_proj, std::forward<_Tp>(__x)));
+ }
+ };
template<typename _Pred, typename _Proj>
- constexpr auto
+ constexpr _Pred_proj<_Pred, _Proj>
__make_pred_proj(_Pred& __pred, _Proj& __proj)
- {
- return [&] <typename _Tp> (_Tp&& __arg) -> bool {
- return std::__invoke(__pred,
- std::__invoke(__proj, std::forward<_Tp>(__arg)));
- };
- }
+ { return {__pred, __proj}; }
} // namespace __detail
struct __all_of_fn
@@ -438,6 +471,254 @@ namespace ranges
inline constexpr __search_n_fn search_n{};
+#if __glibcxx_ranges_starts_ends_with // C++ >= 23
+ struct __starts_with_fn
+ {
+ template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
+ input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
+ typename _Pred = ranges::equal_to,
+ typename _Proj1 = identity, typename _Proj2 = identity>
+ requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2>
+ constexpr bool
+ operator()(_Iter1 __first1, _Sent1 __last1,
+ _Iter2 __first2, _Sent2 __last2, _Pred __pred = {},
+ _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
+ {
+ iter_difference_t<_Iter1> __n1 = -1;
+ iter_difference_t<_Iter2> __n2 = -1;
+ if constexpr (sized_sentinel_for<_Sent1, _Iter1>)
+ __n1 = __last1 - __first1;
+ if constexpr (sized_sentinel_for<_Sent2, _Iter2>)
+ __n2 = __last2 - __first2;
+ return _S_impl(std::move(__first1), __last1, __n1,
+ std::move(__first2), __last2, __n2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2));
+ }
+
+ template<input_range _Range1, input_range _Range2,
+ typename _Pred = ranges::equal_to,
+ typename _Proj1 = identity, typename _Proj2 = identity>
+ requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>,
+ _Pred, _Proj1, _Proj2>
+ constexpr bool
+ operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {},
+ _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
+ {
+ range_difference_t<_Range1> __n1 = -1;
+ range_difference_t<_Range2> __n2 = -1;
+ if constexpr (sized_range<_Range1>)
+ __n1 = ranges::size(__r1);
+ if constexpr (sized_range<_Range2>)
+ __n2 = ranges::size(__r2);
+ return _S_impl(ranges::begin(__r1), ranges::end(__r1), __n1,
+ ranges::begin(__r2), ranges::end(__r2), __n2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2));
+ }
+
+ private:
+ template<typename _Iter1, typename _Sent1, typename _Iter2, typename _Sent2,
+ typename _Pred,
+ typename _Proj1, typename _Proj2>
+ static constexpr bool
+ _S_impl(_Iter1 __first1, _Sent1 __last1, iter_difference_t<_Iter1> __n1,
+ _Iter2 __first2, _Sent2 __last2, iter_difference_t<_Iter2> __n2,
+ _Pred __pred, _Proj1 __proj1, _Proj2 __proj2)
+ {
+ if (__first2 == __last2) [[unlikely]]
+ return true;
+ else if (__n1 == -1 || __n2 == -1)
+ return ranges::mismatch(std::move(__first1), __last1,
+ std::move(__first2), __last2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2)).in2 == __last2;
+ else if (__n1 < __n2)
+ return false;
+ else if constexpr (random_access_iterator<_Iter1>)
+ return ranges::equal(__first1, __first1 + iter_difference_t<_Iter1>(__n2),
+ std::move(__first2), __last2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2));
+ else
+ return ranges::equal(counted_iterator(std::move(__first1),
+ iter_difference_t<_Iter1>(__n2)),
+ default_sentinel,
+ std::move(__first2), __last2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2));
+ }
+
+ friend struct __ends_with_fn;
+ };
+
+ inline constexpr __starts_with_fn starts_with{};
+
+ struct __ends_with_fn
+ {
+ template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
+ input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
+ typename _Pred = ranges::equal_to,
+ typename _Proj1 = identity, typename _Proj2 = identity>
+ requires (forward_iterator<_Iter1> || sized_sentinel_for<_Sent1, _Iter1>)
+ && (forward_iterator<_Iter2> || sized_sentinel_for<_Sent2, _Iter2>)
+ && indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2>
+ constexpr bool
+ operator()(_Iter1 __first1, _Sent1 __last1,
+ _Iter2 __first2, _Sent2 __last2, _Pred __pred = {},
+ _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
+ {
+ iter_difference_t<_Iter1> __n1 = -1;
+ iter_difference_t<_Iter2> __n2 = -1;
+ if constexpr (sized_sentinel_for<_Sent1, _Iter1>)
+ __n1 = __last1 - __first1;
+ if constexpr (sized_sentinel_for<_Sent2, _Iter2>)
+ __n2 = __last2 - __first2;
+ return _S_impl(std::move(__first1), __last1, __n1,
+ std::move(__first2), __last2, __n2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2));
+ }
+
+ template<input_range _Range1, input_range _Range2,
+ typename _Pred = ranges::equal_to,
+ typename _Proj1 = identity, typename _Proj2 = identity>
+ requires (forward_range<_Range1> || sized_range<_Range1>)
+ && (forward_range<_Range2> || sized_range<_Range2>)
+ && indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>,
+ _Pred, _Proj1, _Proj2>
+ constexpr bool
+ operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {},
+ _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
+ {
+ range_difference_t<_Range1> __n1 = -1;
+ range_difference_t<_Range2> __n2 = -1;
+ if constexpr (sized_range<_Range1>)
+ __n1 = ranges::size(__r1);
+ if constexpr (sized_range<_Range2>)
+ __n2 = ranges::size(__r2);
+ return _S_impl(ranges::begin(__r1), ranges::end(__r1), __n1,
+ ranges::begin(__r2), ranges::end(__r2), __n2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2));
+ }
+
+ private:
+ template<typename _Iter1, typename _Sent1,
+ typename _Iter2, typename _Sent2,
+ typename _Pred,
+ typename _Proj1, typename _Proj2>
+ static constexpr bool
+ _S_impl(_Iter1 __first1, _Sent1 __last1, iter_difference_t<_Iter1> __n1,
+ _Iter2 __first2, _Sent2 __last2, iter_difference_t<_Iter2> __n2,
+ _Pred __pred, _Proj1 __proj1, _Proj2 __proj2)
+ {
+ if constexpr (!random_access_iterator<_Iter1>
+ && bidirectional_iterator<_Iter1> && same_as<_Iter1, _Sent1>
+ && bidirectional_iterator<_Iter2> && same_as<_Iter2, _Sent2>)
+ return starts_with._S_impl(std::make_reverse_iterator(__last1),
+ std::make_reverse_iterator(__first1),
+ __n1,
+ std::make_reverse_iterator(__last2),
+ std::make_reverse_iterator(__first2),
+ __n2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2));
+
+ if (__first2 == __last2) [[unlikely]]
+ return true;
+
+ if constexpr (forward_iterator<_Iter2>)
+ if (__n2 == -1)
+ __n2 = ranges::distance(__first2, __last2);
+
+ // __glibcxx_assert(__n2 != -1);
+
+ if (__n1 != -1)
+ {
+ if (__n1 < __n2)
+ return false;
+ auto __shift = __n1 - iter_difference_t<_Iter1>(__n2);
+ if (random_access_iterator<_Iter1>
+ || !bidirectional_iterator<_Iter1>
+ || !same_as<_Iter1, _Sent1>
+ || __shift < __n2)
+ {
+ ranges::advance(__first1, __shift);
+ return ranges::equal(std::move(__first1), __last1,
+ std::move(__first2), __last2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2));
+ }
+ }
+
+ if constexpr (bidirectional_iterator<_Iter1> && same_as<_Iter1, _Sent1>)
+ {
+ _Iter1 __it1 = __last1;
+ if (__n1 != -1)
+ ranges::advance(__it1, -iter_difference_t<_Iter1>(__n2));
+ else
+ {
+ // We can't use ranges::advance if the haystack size is
+ // unknown, since we need to detect and return false if
+ // it's smaller than the needle.
+ iter_difference_t<_Iter2> __m = __n2;
+ while (__m != 0 && __it1 != __first1)
+ {
+ --__m;
+ --__it1;
+ }
+ if (__m != 0)
+ return false;
+ }
+ return ranges::equal(__it1, __last1,
+ std::move(__first2), __last2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2));
+ }
+ else if constexpr (forward_iterator<_Iter1>)
+ {
+ // __glibcxx_assert(__n1 == -1);
+ _Iter1 __prev_first1;
+ __n1 = 0;
+ while (true)
+ {
+ iter_difference_t<_Iter2> __m = __n2;
+ _Iter1 __it1 = __first1;
+ while (__m != 0 && __it1 != __last1)
+ {
+ ++__n1;
+ --__m;
+ ++__it1;
+ }
+ if (__m != 0)
+ {
+ // __glibcxx_assert(__it1 == __last1);
+ if (__n1 < __n2)
+ return false;
+ __first1 = ranges::next(__prev_first1,
+ iter_difference_t<_Iter1>(__n2 - __m));
+ break;
+ }
+ __prev_first1 = __first1;
+ __first1 = __it1;
+ }
+ return ranges::equal(__first1, __last1,
+ std::move(__first2), __last2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2));
+ }
+ else
+ // If the haystack is non-forward then it must be sized, in which case
+ // we already returned via the __n1 != 1 case.
+ __builtin_unreachable();
+ }
+
+ };
+
+ inline constexpr __ends_with_fn ends_with{};
+#endif // __glibcxx_ranges_starts_ends_with
+
struct __find_end_fn
{
template<forward_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
@@ -1013,7 +1294,7 @@ namespace ranges
for (; __first != __last; ++__first)
if (!std::__invoke(__pred, std::__invoke(__proj, *__first)))
{
- *__result = std::move(*__first);
+ *__result = ranges::iter_move(__first);
++__result;
}
@@ -1173,7 +1454,7 @@ namespace ranges
if (!std::__invoke(__comp,
std::__invoke(__proj, *__dest),
std::__invoke(__proj, *__first)))
- *++__dest = std::move(*__first);
+ *++__dest = ranges::iter_move(__first);
return {++__dest, __first};
}
@@ -1218,6 +1499,9 @@ namespace ranges
if (__first == __last)
return {std::move(__first), std::move(__result)};
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4269. unique_copy passes arguments to its predicate backwards
+
// TODO: perform a closer comparison with reference implementations
if constexpr (forward_iterator<_Iter>)
{
@@ -1250,8 +1534,8 @@ namespace ranges
while (++__first != __last)
{
if (!(bool)std::__invoke(__comp,
- std::__invoke(__proj, *__first),
- std::__invoke(__proj, __value)))
+ std::__invoke(__proj, __value),
+ std::__invoke(__proj, *__first)))
{
__value = *__first;
*++__result = __value;
@@ -1555,14 +1839,70 @@ namespace ranges
operator()(_Iter __first, _Sent __last, _Out __out,
iter_difference_t<_Iter> __n, _Gen&& __g) const
{
+ // FIXME: Correctly handle integer-class difference types.
if constexpr (forward_iterator<_Iter>)
{
- // FIXME: Forwarding to std::sample here requires computing __lasti
- // which may take linear time.
- auto __lasti = ranges::next(__first, __last);
- return _GLIBCXX_STD_A::
- sample(std::move(__first), std::move(__lasti), std::move(__out),
- __n, std::forward<_Gen>(__g));
+ using _Size = iter_difference_t<_Iter>;
+ using __distrib_type = uniform_int_distribution<_Size>;
+ using __param_type = typename __distrib_type::param_type;
+ using _USize = __detail::__make_unsigned_like_t<_Size>;
+ using __uc_type
+ = common_type_t<typename remove_reference_t<_Gen>::result_type, _USize>;
+
+ if (__first == __last)
+ return __out;
+
+ __distrib_type __d{};
+ _Size __unsampled_sz = ranges::distance(__first, __last);
+ __n = std::min(__n, __unsampled_sz);
+
+ // If possible, we use __gen_two_uniform_ints to efficiently produce
+ // two random numbers using a single distribution invocation:
+
+ const __uc_type __urngrange = __g.max() - __g.min();
+ if (__urngrange / __uc_type(__unsampled_sz) >= __uc_type(__unsampled_sz))
+ // I.e. (__urngrange >= __unsampled_sz * __unsampled_sz) but without
+ // wrapping issues.
+ {
+ while (__n != 0 && __unsampled_sz >= 2)
+ {
+ const pair<_Size, _Size> __p =
+ __gen_two_uniform_ints(__unsampled_sz, __unsampled_sz - 1, __g);
+
+ --__unsampled_sz;
+ if (__p.first < __n)
+ {
+ *__out = *__first;
+ ++__out;
+ --__n;
+ }
+
+ ++__first;
+
+ if (__n == 0) break;
+
+ --__unsampled_sz;
+ if (__p.second < __n)
+ {
+ *__out = *__first;
+ ++__out;
+ --__n;
+ }
+
+ ++__first;
+ }
+ }
+
+ // The loop above is otherwise equivalent to this one-at-a-time version:
+
+ for (; __n != 0; ++__first)
+ if (__d(__g, __param_type{0, --__unsampled_sz}) < __n)
+ {
+ *__out = *__first;
+ ++__out;
+ --__n;
+ }
+ return __out;
}
else
{
@@ -1583,7 +1923,7 @@ namespace ranges
if (__k < __n)
__out[__k] = *__first;
}
- return __out + __sample_sz;
+ return __out + iter_difference_t<_Out>(__sample_sz);
}
}
@@ -1612,9 +1952,61 @@ namespace ranges
_Iter
operator()(_Iter __first, _Sent __last, _Gen&& __g) const
{
- auto __lasti = ranges::next(__first, __last);
- std::shuffle(std::move(__first), __lasti, std::forward<_Gen>(__g));
- return __lasti;
+ // FIXME: Correctly handle integer-class difference types.
+ if (__first == __last)
+ return __first;
+
+ using _DistanceType = iter_difference_t<_Iter>;
+ using __ud_type = __detail::__make_unsigned_like_t<_DistanceType>;
+ using __distr_type = std::uniform_int_distribution<__ud_type>;
+ using __p_type = typename __distr_type::param_type;
+
+ using __uc_type
+ = common_type_t<typename remove_reference_t<_Gen>::result_type, __ud_type>;
+
+ const __uc_type __urngrange = __g.max() - __g.min();
+ const __uc_type __urange = __uc_type(__last - __first);
+
+ if (__urngrange / __urange >= __urange)
+ // I.e. (__urngrange >= __urange * __urange) but without wrap issues.
+ {
+ _Iter __i = __first + 1;
+
+ // Since we know the range isn't empty, an even number of elements
+ // means an uneven number of elements /to swap/, in which case we
+ // do the first one up front:
+
+ if ((__urange % 2) == 0)
+ {
+ __distr_type __d{0, 1};
+ ranges::iter_swap(__i++, __first + __d(__g));
+ }
+
+ // Now we know that __last - __i is even, so we do the rest in pairs,
+ // using a single distribution invocation to produce swap positions
+ // for two successive elements at a time:
+
+ while (__i != __last)
+ {
+ const __uc_type __swap_range = __uc_type(__i - __first) + 1;
+
+ const pair<__uc_type, __uc_type> __pospos =
+ __gen_two_uniform_ints(__swap_range, __swap_range + 1, __g);
+
+ ranges::iter_swap(__i++, __first + __pospos.first);
+ ranges::iter_swap(__i++, __first + __pospos.second);
+ }
+
+ return __i;
+ }
+
+ __distr_type __d;
+
+ _Iter __i = __first + 1;
+ for (; __i != __last; ++__i)
+ ranges::iter_swap(__i, __first + __d(__g, __p_type(0, __i - __first)));
+
+ return __i;
}
template<random_access_range _Range, typename _Gen>
@@ -1630,6 +2022,28 @@ namespace ranges
inline constexpr __shuffle_fn shuffle{};
+ namespace __detail
+ {
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __push_heap(_Iter __first,
+ iter_difference_t<_Iter> __holeIndex,
+ iter_difference_t<_Iter> __topIndex,
+ iter_value_t<_Iter> __value,
+ _Comp __comp)
+ {
+ auto __parent = (__holeIndex - 1) / 2;
+ while (__holeIndex > __topIndex
+ && __comp(*(__first + __parent), __value))
+ {
+ *(__first + __holeIndex) = ranges::iter_move(__first + __parent);
+ __holeIndex = __parent;
+ __parent = (__holeIndex - 1) / 2;
+ }
+ *(__first + __holeIndex) = std::move(__value);
+ }
+ } // namespace __detail
+
struct __push_heap_fn
{
template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
@@ -1639,10 +2053,17 @@ namespace ranges
operator()(_Iter __first, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
- auto __lasti = ranges::next(__first, __last);
- std::push_heap(__first, __lasti,
- __detail::__make_comp_proj(__comp, __proj));
- return __lasti;
+ if constexpr (!same_as<_Iter, _Sent>)
+ return (*this)(__first, ranges::next(__first, __last),
+ std::move(__comp), std::move(__proj));
+ else
+ {
+ auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
+ __detail::__push_heap(__first, (__last - __first) - 1,
+ 0, ranges::iter_move(__last - 1),
+ __comp_proj);
+ return __last;
+ }
}
template<random_access_range _Range,
@@ -1658,6 +2079,48 @@ namespace ranges
inline constexpr __push_heap_fn push_heap{};
+ namespace __detail
+ {
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __adjust_heap(_Iter __first,
+ iter_difference_t<_Iter> __holeIndex,
+ iter_difference_t<_Iter> __len,
+ iter_value_t<_Iter> __value,
+ _Comp __comp)
+ {
+ auto __topIndex = __holeIndex;
+ auto __secondChild = __holeIndex;
+ while (__secondChild < (__len - 1) / 2)
+ {
+ __secondChild = 2 * (__secondChild + 1);
+ if (__comp(*(__first + __secondChild),
+ *(__first + (__secondChild - 1))))
+ __secondChild--;
+ *(__first + __holeIndex) = ranges::iter_move(__first + __secondChild);
+ __holeIndex = __secondChild;
+ }
+ if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
+ {
+ __secondChild = 2 * (__secondChild + 1);
+ *(__first + __holeIndex) = ranges::iter_move(__first + (__secondChild - 1));
+ __holeIndex = __secondChild - 1;
+ }
+ __detail::__push_heap(__first, __holeIndex, __topIndex,
+ std::move(__value), __comp);
+ }
+
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __pop_heap(_Iter __first, _Iter __last, _Iter __result, _Comp __comp)
+ {
+ iter_value_t<_Iter> __value = ranges::iter_move(__result);
+ *__result = ranges::iter_move(__first);
+ __detail::__adjust_heap(__first, 0, __last - __first,
+ std::move(__value), __comp);
+ }
+ } // namespace __detail
+
struct __pop_heap_fn
{
template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
@@ -1667,10 +2130,18 @@ namespace ranges
operator()(_Iter __first, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
- auto __lasti = ranges::next(__first, __last);
- std::pop_heap(__first, __lasti,
- __detail::__make_comp_proj(__comp, __proj));
- return __lasti;
+ if constexpr (!same_as<_Iter, _Sent>)
+ return (*this)(__first, ranges::next(__first, __last),
+ std::move(__comp), std::move(__proj));
+ else
+ {
+ if (__last - __first > 1)
+ {
+ auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
+ __detail::__pop_heap(__first, __last - 1, __last - 1, __comp_proj);
+ }
+ return __last;
+ }
}
template<random_access_range _Range,
@@ -1695,10 +2166,29 @@ namespace ranges
operator()(_Iter __first, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
- auto __lasti = ranges::next(__first, __last);
- std::make_heap(__first, __lasti,
- __detail::__make_comp_proj(__comp, __proj));
- return __lasti;
+ if constexpr (!same_as<_Iter, _Sent>)
+ return (*this)(__first, ranges::next(__first, __last),
+ std::move(__comp), std::move(__proj));
+ else
+ {
+ const auto __len = __last - __first;
+ if (__len < 2)
+ return __last;
+
+ auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
+ auto __parent = (__len - 2) / 2;
+ while (true)
+ {
+ iter_value_t<_Iter> __value = ranges::iter_move(__first + __parent);
+ __detail::__adjust_heap(__first, __parent, __len,
+ std::move(__value),
+ __comp_proj);
+ if (__parent == 0)
+ break;
+ __parent--;
+ }
+ return __last;
+ }
}
template<random_access_range _Range,
@@ -1723,10 +2213,20 @@ namespace ranges
operator()(_Iter __first, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
- auto __lasti = ranges::next(__first, __last);
- std::sort_heap(__first, __lasti,
- __detail::__make_comp_proj(__comp, __proj));
- return __lasti;
+ if constexpr (!same_as<_Iter, _Sent>)
+ return (*this)(__first, ranges::next(__first, __last),
+ std::move(__comp), std::move(__proj));
+ else
+ {
+ auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
+ _Iter __ret = __last;
+ while (__last - __first > 1)
+ {
+ --__last;
+ __detail::__pop_heap(__first, __last, __last, __comp_proj);
+ }
+ return __ret;
+ }
}
template<random_access_range _Range,
@@ -1809,6 +2309,154 @@ namespace ranges
inline constexpr __is_heap_fn is_heap{};
+ namespace __detail
+ {
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __move_median_to_first(_Iter __result, _Iter __a, _Iter __b, _Iter __c,
+ _Comp __comp)
+ {
+ if (__comp(*__a, *__b))
+ {
+ if (__comp(*__b, *__c))
+ ranges::iter_swap(__result, __b);
+ else if (__comp(*__a, *__c))
+ ranges::iter_swap(__result, __c);
+ else
+ ranges::iter_swap(__result, __a);
+ }
+ else if (__comp(*__a, *__c))
+ ranges::iter_swap(__result, __a);
+ else if (__comp(*__b, *__c))
+ ranges::iter_swap(__result, __c);
+ else
+ ranges::iter_swap(__result, __b);
+ }
+
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __unguarded_linear_insert(_Iter __last, _Comp __comp)
+ {
+ iter_value_t<_Iter> __val = ranges::iter_move(__last);
+ _Iter __next = __last;
+ --__next;
+ while (__comp(__val, *__next))
+ {
+ *__last = ranges::iter_move(__next);
+ __last = __next;
+ --__next;
+ }
+ *__last = std::move(__val);
+ }
+
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __insertion_sort(_Iter __first, _Iter __last, _Comp __comp)
+ {
+ if (__first == __last)
+ return;
+
+ for (_Iter __i = __first + 1; __i != __last; ++__i)
+ {
+ if (__comp(*__i, *__first))
+ {
+ iter_value_t<_Iter> __val = ranges::iter_move(__i);
+ ranges::move_backward(__first, __i, __i + 1);
+ *__first = std::move(__val);
+ }
+ else
+ __detail::__unguarded_linear_insert(__i, __comp);
+ }
+ }
+
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __unguarded_insertion_sort(_Iter __first, _Iter __last, _Comp __comp)
+ {
+ for (_Iter __i = __first; __i != __last; ++__i)
+ __detail::__unguarded_linear_insert(__i, __comp);
+ }
+
+ inline constexpr int __sort_threshold = 16;
+
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __final_insertion_sort(_Iter __first, _Iter __last, _Comp __comp)
+ {
+ if (__last - __first > __sort_threshold)
+ {
+ __detail::__insertion_sort(__first, __first + __sort_threshold, __comp);
+ __detail::__unguarded_insertion_sort(__first + __sort_threshold, __last,
+ __comp);
+ }
+ else
+ __detail::__insertion_sort(__first, __last, __comp);
+ }
+
+ template<typename _Iter, typename _Comp>
+ constexpr _Iter
+ __unguarded_partition(_Iter __first, _Iter __last, _Iter __pivot, _Comp __comp)
+ {
+ while (true)
+ {
+ while (__comp(*__first, *__pivot))
+ ++__first;
+ --__last;
+ while (__comp(*__pivot, *__last))
+ --__last;
+ if (!(__first < __last))
+ return __first;
+ ranges::iter_swap(__first, __last);
+ ++__first;
+ }
+ }
+
+ template<typename _Iter, typename _Comp>
+ constexpr _Iter
+ __unguarded_partition_pivot(_Iter __first, _Iter __last, _Comp __comp)
+ {
+ _Iter __mid = __first + (__last - __first) / 2;
+ __detail::__move_median_to_first(__first, __first + 1, __mid, __last - 1, __comp);
+ return __detail::__unguarded_partition(__first + 1, __last, __first, __comp);
+ }
+
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __heap_select(_Iter __first, _Iter __middle, _Iter __last, _Comp __comp)
+ {
+ ranges::make_heap(__first, __middle, __comp);
+ for (_Iter __i = __middle; __i < __last; ++__i)
+ if (__comp(*__i, *__first))
+ __detail::__pop_heap(__first, __middle, __i, __comp);
+ }
+
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __partial_sort(_Iter __first, _Iter __middle, _Iter __last, _Comp __comp)
+ {
+ __detail::__heap_select(__first, __middle, __last, __comp);
+ ranges::sort_heap(__first, __middle, __comp);
+ }
+
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __introsort_loop(_Iter __first, _Iter __last, unsigned __depth_limit, _Comp __comp)
+ {
+ while (__last - __first > __sort_threshold)
+ {
+ if (__depth_limit == 0)
+ {
+ __detail::__partial_sort(__first, __last, __last, __comp);
+ return;
+ }
+ --__depth_limit;
+ _Iter __cut = __detail::__unguarded_partition_pivot(__first, __last, __comp);
+ __detail::__introsort_loop(__cut, __last, __depth_limit, __comp);
+ __last = __cut;
+ }
+ }
+ } // namespace __detail
+
struct __sort_fn
{
template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
@@ -1818,10 +2466,21 @@ namespace ranges
operator()(_Iter __first, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
- auto __lasti = ranges::next(__first, __last);
- _GLIBCXX_STD_A::sort(std::move(__first), __lasti,
- __detail::__make_comp_proj(__comp, __proj));
- return __lasti;
+ if constexpr (!same_as<_Iter, _Sent>)
+ return (*this)(__first, ranges::next(__first, __last),
+ std::move(__comp), std::move(__proj));
+ else
+ {
+ if (__first != __last)
+ {
+ auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
+ auto __n = __detail::__to_unsigned_like(__last - __first);
+ unsigned __depth_limit = (std::__bit_width(__n) - 1) * 2;
+ __detail::__introsort_loop(__first, __last, __depth_limit, __comp_proj);
+ __detail::__final_insertion_sort(__first, __last, __comp_proj);
+ }
+ return __last;
+ }
}
template<random_access_range _Range,
@@ -1837,6 +2496,169 @@ namespace ranges
inline constexpr __sort_fn sort{};
+ namespace __detail
+ {
+ // This is a helper function for the __merge_sort_loop routines.
+ template<typename _Iter, typename _Out, typename _Comp>
+ _Out
+ __move_merge(_Iter __first1, _Iter __last1,
+ _Iter __first2, _Iter __last2,
+ _Out __result, _Comp __comp)
+ {
+ while (__first1 != __last1 && __first2 != __last2)
+ {
+ if (__comp(*__first2, *__first1))
+ {
+ *__result = ranges::iter_move(__first2);
+ ++__first2;
+ }
+ else
+ {
+ *__result = ranges::iter_move(__first1);
+ ++__first1;
+ }
+ ++__result;
+ }
+ return ranges::move(__first2, __last2,
+ ranges::move(__first1, __last1, __result).out).out;
+ }
+
+ template<typename _Iter, typename _Out, typename _Distance, typename _Comp>
+ void
+ __merge_sort_loop(_Iter __first, _Iter __last, _Out __result,
+ _Distance __step_size, _Comp __comp)
+ {
+ const _Distance __two_step = 2 * __step_size;
+
+ while (__last - __first >= __two_step)
+ {
+ __result = __detail::__move_merge(__first, __first + __step_size,
+ __first + __step_size,
+ __first + __two_step,
+ __result, __comp);
+ __first += __two_step;
+ }
+ __step_size = ranges::min(_Distance(__last - __first), __step_size);
+
+ __detail::__move_merge(__first, __first + __step_size,
+ __first + __step_size, __last, __result, __comp);
+ }
+
+ template<typename _Iter, typename _Distance, typename _Compare>
+ constexpr void
+ __chunk_insertion_sort(_Iter __first, _Iter __last,
+ _Distance __chunk_size, _Compare __comp)
+ {
+ while (__last - __first >= __chunk_size)
+ {
+ __detail::__insertion_sort(__first, __first + __chunk_size, __comp);
+ __first += __chunk_size;
+ }
+ __detail::__insertion_sort(__first, __last, __comp);
+ }
+
+ template<typename _Iter, typename _Pointer, typename _Comp>
+ void
+ __merge_sort_with_buffer(_Iter __first, _Iter __last,
+ _Pointer __buffer, _Comp __comp)
+ {
+ using _Distance = iter_difference_t<_Iter>;
+
+ const _Distance __len = __last - __first;
+ const _Pointer __buffer_last = __buffer + ptrdiff_t(__len);
+
+ constexpr int __chunk_size = 7;
+ _Distance __step_size = __chunk_size;
+ __detail::__chunk_insertion_sort(__first, __last, __step_size, __comp);
+
+ while (__step_size < __len)
+ {
+ __detail::__merge_sort_loop(__first, __last, __buffer,
+ __step_size, __comp);
+ __step_size *= 2;
+ __detail::__merge_sort_loop(__buffer, __buffer_last, __first,
+ ptrdiff_t(__step_size), __comp);
+ __step_size *= 2;
+ }
+ }
+
+ template<typename _Iter, typename _Pointer, typename _Comp>
+ void
+ __merge_adaptive(_Iter __first, _Iter __middle, _Iter __last,
+ iter_difference_t<_Iter> __len1,
+ iter_difference_t<_Iter> __len2,
+ _Pointer __buffer, _Comp __comp); // defined near inplace_merge
+
+ template<typename _Iter, typename _Distance, typename _Pointer, typename _Comp>
+ void
+ __merge_adaptive_resize(_Iter __first, _Iter __middle, _Iter __last,
+ _Distance __len1, _Distance __len2,
+ _Pointer __buffer, _Distance __buffer_size,
+ _Comp __comp); // defined near inplace_merge
+
+ template<typename _Iter, typename _Distance, typename _Comp>
+ constexpr void
+ __merge_without_buffer(_Iter __first, _Iter __middle, _Iter __last,
+ _Distance __len1, _Distance __len2,
+ _Comp __comp); // defined near inplace_merge
+
+ template<typename _Iter, typename _Pointer, typename _Comp>
+ void
+ __stable_sort_adaptive(_Iter __first, _Iter __middle, _Iter __last,
+ _Pointer __buffer, _Comp __comp)
+ {
+ __detail::__merge_sort_with_buffer(__first, __middle, __buffer, __comp);
+ __detail::__merge_sort_with_buffer(__middle, __last, __buffer, __comp);
+
+ __detail::__merge_adaptive(__first, __middle, __last,
+ __middle - __first, __last - __middle,
+ __buffer, __comp);
+ }
+
+ template<typename _Iter, typename _Pointer, typename _Distance, typename _Comp>
+ void
+ __stable_sort_adaptive_resize(_Iter __first, _Iter __last,
+ _Pointer __buffer, _Distance __buffer_size,
+ _Comp __comp)
+ {
+ const _Distance __len = (__last - __first + 1) / 2;
+ const _Iter __middle = __first + __len;
+ if (__len > __buffer_size)
+ {
+ __detail::__stable_sort_adaptive_resize(__first, __middle, __buffer,
+ __buffer_size, __comp);
+ __detail::__stable_sort_adaptive_resize(__middle, __last, __buffer,
+ __buffer_size, __comp);
+ __detail::__merge_adaptive_resize(__first, __middle, __last,
+ _Distance(__middle - __first),
+ _Distance(__last - __middle),
+ __buffer, __buffer_size,
+ __comp);
+ }
+ else
+ __detail::__stable_sort_adaptive(__first, __middle, __last,
+ __buffer, __comp);
+ }
+
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __inplace_stable_sort(_Iter __first, _Iter __last, _Comp __comp)
+ {
+ if (__last - __first < 15)
+ {
+ __detail::__insertion_sort(__first, __last, __comp);
+ return;
+ }
+ _Iter __middle = __first + (__last - __first) / 2;
+ __detail::__inplace_stable_sort(__first, __middle, __comp);
+ __detail::__inplace_stable_sort(__middle, __last, __comp);
+ __detail::__merge_without_buffer(__first, __middle, __last,
+ __middle - __first,
+ __last - __middle,
+ __comp);
+ }
+ } // namespace __detail
+
struct __stable_sort_fn
{
template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
@@ -1847,10 +2669,46 @@ namespace ranges
operator()(_Iter __first, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
- auto __lasti = ranges::next(__first, __last);
- std::stable_sort(std::move(__first), __lasti,
- __detail::__make_comp_proj(__comp, __proj));
- return __lasti;
+ if constexpr (!same_as<_Iter, _Sent>)
+ return (*this)(__first, ranges::next(__first, __last),
+ std::move(__comp), std::move(__proj));
+ else
+ {
+ using _DistanceType = iter_difference_t<_Iter>;
+
+ if (__first == __last)
+ return __last;
+
+ auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
+
+#if _GLIBCXX_HOSTED
+# if __glibcxx_constexpr_algorithms >= 202306L // >= C++26
+ if consteval {
+ __detail::__inplace_stable_sort(__first, __last, __comp_proj);
+ return __last;
+ }
+# endif
+
+ typedef _Temporary_buffer<_Iter, iter_value_t<_Iter>> _TmpBuf;
+ // __stable_sort_adaptive sorts the range in two halves,
+ // so the buffer only needs to fit half the range at once.
+ _TmpBuf __buf(__first, ptrdiff_t((__last - __first + 1) / 2));
+
+ if (__buf._M_requested_size() == __buf.size()) [[likely]]
+ __detail::__stable_sort_adaptive(__first,
+ __first + _DistanceType(__buf.size()),
+ __last, __buf.begin(), __comp_proj);
+ else if (__buf.begin()) [[unlikely]]
+ __detail::__inplace_stable_sort(__first, __last, __comp_proj);
+ else
+ __detail::__stable_sort_adaptive_resize(__first, __last, __buf.begin(),
+ _DistanceType(__buf.size()),
+ __comp_proj);
+#else
+ __detail::__inplace_stable_sort(__first, __last, __comp_proj);
+#endif
+ return __last;
+ }
}
template<random_access_range _Range,
@@ -2055,6 +2913,33 @@ namespace ranges
inline constexpr __is_sorted_fn is_sorted{};
+ namespace __detail
+ {
+ template<typename _Iter, typename _Comp>
+ constexpr void
+ __introselect(_Iter __first, _Iter __nth, _Iter __last,
+ iter_difference_t<_Iter> __depth_limit, _Comp __comp)
+ {
+ while (__last - __first > 3)
+ {
+ if (__depth_limit == 0)
+ {
+ __detail::__heap_select(__first, __nth + 1, __last, __comp);
+ // Place the nth largest element in its final position.
+ ranges::iter_swap(__first, __nth);
+ return;
+ }
+ --__depth_limit;
+ _Iter __cut = __detail::__unguarded_partition_pivot(__first, __last, __comp);
+ if (__cut <= __nth)
+ __first = __cut;
+ else
+ __last = __cut;
+ }
+ __detail::__insertion_sort(__first, __last, __comp);
+ }
+ } // namespace __detail
+
struct __nth_element_fn
{
template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
@@ -2064,11 +2949,21 @@ namespace ranges
operator()(_Iter __first, _Iter __nth, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
- auto __lasti = ranges::next(__first, __last);
- _GLIBCXX_STD_A::nth_element(std::move(__first), std::move(__nth),
- __lasti,
- __detail::__make_comp_proj(__comp, __proj));
- return __lasti;
+ if constexpr (!same_as<_Iter, _Sent>)
+ return (*this)(__first, __nth, ranges::next(__first, __last),
+ std::move(__comp), std::move(__proj));
+ else
+ {
+ if (__first == __last || __nth == __last)
+ return __last;
+
+ auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
+ auto __n = __detail::__to_unsigned_like(__last - __first);
+ __detail::__introselect(__first, __nth, __last,
+ std::__bit_width(__n) * 2,
+ __comp_proj);
+ return __last;
+ }
}
template<random_access_range _Range,
@@ -2383,6 +3278,80 @@ namespace ranges
inline constexpr __partition_fn partition{};
#if _GLIBCXX_HOSTED
+ namespace __detail
+ {
+ // Like find_if_not(), but uses and updates a count of the
+ // remaining range length instead of comparing against an end
+ // iterator.
+ template<typename _Iter, typename _Pred, typename _Distance>
+ constexpr _Iter
+ __find_if_not_n(_Iter __first, _Distance& __len, _Pred __pred)
+ {
+ for (; __len; --__len, (void) ++__first)
+ if (!__pred(*__first))
+ break;
+ return __first;
+ }
+
+ template<typename _Iter, typename _Sent, typename _Pointer,
+ typename _Pred, typename _Distance>
+ constexpr subrange<_Iter>
+ __stable_partition_adaptive(_Iter __first, _Sent __last,
+ _Pred __pred, _Distance __len,
+ _Pointer __buffer,
+ _Distance __buffer_size)
+ {
+ if (__len == 1)
+ return {__first, ranges::next(__first, 1)};
+
+ if (__len <= __buffer_size)
+ {
+ _Iter __result1 = __first;
+ _Pointer __result2 = __buffer;
+
+ // The precondition guarantees that !__pred(__first), so
+ // move that element to the buffer before starting the loop.
+ // This ensures that we only call __pred once per element.
+ *__result2 = ranges::iter_move(__first);
+ ++__result2;
+ ++__first;
+ for (; __first != __last; ++__first)
+ if (__pred(*__first))
+ {
+ *__result1 = ranges::iter_move(__first);
+ ++__result1;
+ }
+ else
+ {
+ *__result2 = ranges::iter_move(__first);
+ ++__result2;
+ }
+
+ ranges::move(__buffer, __result2, __result1);
+ return {__result1, __first};
+ }
+
+ _Iter __middle = __first;
+ ranges::advance(__middle, __len / 2);
+ _Iter __left_split
+ = __detail::__stable_partition_adaptive(__first, __middle, __pred,
+ __len / 2, __buffer,
+ __buffer_size).begin();
+
+ // Advance past true-predicate values to satisfy this
+ // function's preconditions.
+ _Distance __right_len = __len - __len / 2;
+ _Iter __right_split = __detail::__find_if_not_n(__middle, __right_len, __pred);
+
+ if (__right_len)
+ __right_split
+ = __detail::__stable_partition_adaptive(__right_split, __last, __pred,
+ __right_len, __buffer, __buffer_size).begin();
+
+ return ranges::rotate(__left_split, __middle, __right_split);
+ }
+ } // namespace __detail
+
struct __stable_partition_fn
{
template<bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent,
@@ -2394,11 +3363,33 @@ namespace ranges
operator()(_Iter __first, _Sent __last,
_Pred __pred, _Proj __proj = {}) const
{
- auto __lasti = ranges::next(__first, __last);
- auto __middle
- = std::stable_partition(std::move(__first), __lasti,
- __detail::__make_pred_proj(__pred, __proj));
- return {std::move(__middle), std::move(__lasti)};
+ __first = ranges::find_if_not(__first, __last, __pred, __proj);
+
+ if (__first == __last)
+ return {__first, __first};
+
+ using _DistanceType = iter_difference_t<_Iter>;
+ const _DistanceType __len = ranges::distance(__first, __last);
+
+ auto __pred_proj = __detail::__make_pred_proj(__pred, __proj);
+
+#if __glibcxx_constexpr_algorithms >= 202306L // >= C++26
+ if consteval {
+ // Simulate a _Temporary_buffer of length 1:
+ iter_value_t<_Iter> __buf = ranges::iter_move(__first);
+ *__first = std::move(__buf);
+ return __detail::__stable_partition_adaptive(__first, __last,
+ __pred_proj,
+ __len, &__buf,
+ _DistanceType(1));
+ }
+#endif
+
+ _Temporary_buffer<_Iter, iter_value_t<_Iter>> __buf(__first, ptrdiff_t(__len));
+ return __detail::__stable_partition_adaptive(__first, __last,
+ __pred_proj,
+ __len, __buf.begin(),
+ _DistanceType(__buf.size()));
}
template<bidirectional_range _Range, typename _Proj = identity,
@@ -2594,6 +3585,215 @@ namespace ranges
inline constexpr __merge_fn merge{};
+ namespace __detail
+ {
+ template<typename _Iter1, typename _Iter2, typename _Out, typename _Comp>
+ void
+ __move_merge_adaptive(_Iter1 __first1, _Iter1 __last1,
+ _Iter2 __first2, _Iter2 __last2,
+ _Out __result, _Comp __comp)
+ {
+ while (__first1 != __last1 && __first2 != __last2)
+ {
+ if (__comp(*__first2, *__first1))
+ {
+ *__result = ranges::iter_move(__first2);
+ ++__first2;
+ }
+ else
+ {
+ *__result = ranges::iter_move(__first1);
+ ++__first1;
+ }
+ ++__result;
+ }
+ if (__first1 != __last1)
+ ranges::move(__first1, __last1, __result);
+ }
+
+ template<typename _Iter1, typename _Iter2, typename _Iter3, typename _Comp>
+ void
+ __move_merge_adaptive_backward(_Iter1 __first1, _Iter1 __last1,
+ _Iter2 __first2, _Iter2 __last2,
+ _Iter3 __result, _Comp __comp)
+ {
+ if (__first1 == __last1)
+ {
+ ranges::move_backward(__first2, __last2, __result);
+ return;
+ }
+ else if (__first2 == __last2)
+ return;
+
+ --__last1;
+ --__last2;
+ while (true)
+ {
+ if (__comp(*__last2, *__last1))
+ {
+ *--__result = ranges::iter_move(__last1);
+ if (__first1 == __last1)
+ {
+ ranges::move_backward(__first2, ++__last2, __result);
+ return;
+ }
+ --__last1;
+ }
+ else
+ {
+ *--__result = ranges::iter_move(__last2);
+ if (__first2 == __last2)
+ return;
+ --__last2;
+ }
+ }
+ }
+
+ template<typename _Iter1, typename _Iter2>
+ _Iter1
+ __rotate_adaptive(_Iter1 __first, _Iter1 __middle, _Iter1 __last,
+ iter_difference_t<_Iter1> __len1,
+ iter_difference_t<_Iter1> __len2,
+ _Iter2 __buffer,
+ iter_difference_t<_Iter1> __buffer_size)
+ {
+ _Iter2 __buffer_end;
+ if (__len1 > __len2 && __len2 <= __buffer_size)
+ {
+ if (__len2)
+ {
+ __buffer_end = ranges::move(__middle, __last, __buffer).out;
+ ranges::move_backward(__first, __middle, __last);
+ return ranges::move(__buffer, __buffer_end, __first).out;
+ }
+ else
+ return __first;
+ }
+ else if (__len1 <= __buffer_size)
+ {
+ if (__len1)
+ {
+ __buffer_end = ranges::move(__first, __middle, __buffer).out;
+ ranges::move(__middle, __last, __first);
+ return ranges::move_backward(__buffer, __buffer_end, __last).out;
+ }
+ else
+ return __last;
+ }
+ else
+ return ranges::rotate(__first, __middle, __last).begin();
+ }
+
+ template<typename _Iter, typename _Pointer, typename _Comp>
+ void
+ __merge_adaptive(_Iter __first, _Iter __middle, _Iter __last,
+ iter_difference_t<_Iter> __len1,
+ iter_difference_t<_Iter> __len2,
+ _Pointer __buffer, _Comp __comp)
+ {
+ if (__len1 <= __len2)
+ {
+ _Pointer __buffer_end = ranges::move(__first, __middle, __buffer).out;
+ __detail::__move_merge_adaptive(__buffer, __buffer_end, __middle, __last,
+ __first, __comp);
+ }
+ else
+ {
+ _Pointer __buffer_end = ranges::move(__middle, __last, __buffer).out;
+ __detail::__move_merge_adaptive_backward(__first, __middle, __buffer,
+ __buffer_end, __last, __comp);
+ }
+ }
+
+ template<typename _Iter, typename _Distance, typename _Pointer, typename _Comp>
+ void
+ __merge_adaptive_resize(_Iter __first, _Iter __middle, _Iter __last,
+ _Distance __len1, _Distance __len2,
+ _Pointer __buffer, _Distance __buffer_size,
+ _Comp __comp)
+ {
+ if (__len1 <= __buffer_size || __len2 <= __buffer_size)
+ __detail::__merge_adaptive(__first, __middle, __last,
+ __len1, __len2, __buffer, __comp);
+ else
+ {
+ _Iter __first_cut = __first;
+ _Iter __second_cut = __middle;
+ _Distance __len11 = 0;
+ _Distance __len22 = 0;
+ if (__len1 > __len2)
+ {
+ __len11 = __len1 / 2;
+ ranges::advance(__first_cut, __len11);
+ __second_cut = ranges::lower_bound(__middle, __last, *__first_cut,
+ __comp);
+ __len22 = ranges::distance(__middle, __second_cut);
+ }
+ else
+ {
+ __len22 = __len2 / 2;
+ ranges::advance(__second_cut, __len22);
+ __first_cut = ranges::upper_bound(__first, __middle, *__second_cut,
+ __comp);
+ __len11 = ranges::distance(__first, __first_cut);
+ }
+
+ _Iter __new_middle
+ = __detail::__rotate_adaptive(__first_cut, __middle, __second_cut,
+ _Distance(__len1 - __len11), __len22,
+ __buffer, __buffer_size);
+ __detail::__merge_adaptive_resize(__first, __first_cut, __new_middle,
+ __len11, __len22,
+ __buffer, __buffer_size, __comp);
+ __detail::__merge_adaptive_resize(__new_middle, __second_cut, __last,
+ _Distance(__len1 - __len11),
+ _Distance(__len2 - __len22),
+ __buffer, __buffer_size, __comp);
+ }
+ }
+
+ template<typename _Iter, typename _Distance, typename _Comp>
+ constexpr void
+ __merge_without_buffer(_Iter __first, _Iter __middle, _Iter __last,
+ _Distance __len1, _Distance __len2, _Comp __comp)
+ {
+ if (__len1 == 0 || __len2 == 0)
+ return;
+
+ if (__len1 + __len2 == 2)
+ {
+ if (__comp(*__middle, *__first))
+ ranges::iter_swap(__first, __middle);
+ return;
+ }
+
+ _Iter __first_cut = __first;
+ _Iter __second_cut = __middle;
+ _Distance __len11 = 0;
+ _Distance __len22 = 0;
+ if (__len1 > __len2)
+ {
+ __len11 = __len1 / 2;
+ ranges::advance(__first_cut, __len11);
+ __second_cut = ranges::lower_bound(__middle, __last, *__first_cut, __comp);
+ __len22 = ranges::distance(__middle, __second_cut);
+ }
+ else
+ {
+ __len22 = __len2 / 2;
+ ranges::advance(__second_cut, __len22);
+ __first_cut = ranges::upper_bound(__first, __middle, *__second_cut, __comp);
+ __len11 = ranges::distance(__first, __first_cut);
+ }
+
+ _Iter __new_middle = ranges::rotate(__first_cut, __middle, __second_cut).begin();
+ __detail::__merge_without_buffer(__first, __first_cut, __new_middle,
+ __len11, __len22, __comp);
+ __detail::__merge_without_buffer(__new_middle, __second_cut, __last,
+ __len1 - __len11, __len2 - __len22, __comp);
+ }
+ } // namespace __detail
+
struct __inplace_merge_fn
{
template<bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent,
@@ -2605,10 +3805,50 @@ namespace ranges
operator()(_Iter __first, _Iter __middle, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
- auto __lasti = ranges::next(__first, __last);
- std::inplace_merge(std::move(__first), std::move(__middle), __lasti,
- __detail::__make_comp_proj(__comp, __proj));
- return __lasti;
+ if constexpr (!same_as<_Iter, _Sent>)
+ return (*this)(__first, __middle, ranges::next(__middle, __last),
+ std::move(__comp), std::move(__proj));
+ else
+ {
+ using _DistanceType = iter_difference_t<_Iter>;
+
+ if (__first == __middle || __middle == __last)
+ return __last;
+
+ const _DistanceType __len1 = ranges::distance(__first, __middle);
+ const _DistanceType __len2 = ranges::distance(__middle, __last);
+
+ auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
+
+#if _GLIBCXX_HOSTED
+# if __glibcxx_constexpr_algorithms >= 202306L // >= C++26
+ if consteval {
+ __detail::__merge_without_buffer(__first, __middle, __last,
+ __len1, __len2, __comp_proj);
+ return __last;
+ }
+# endif
+ using _TmpBuf = _Temporary_buffer<_Iter, iter_value_t<_Iter>>;
+ // __merge_adaptive will use a buffer for the smaller of
+ // [first,middle) and [middle,last).
+ _TmpBuf __buf(__first, ptrdiff_t(ranges::min(__len1, __len2)));
+
+ if (__buf.size() == __buf._M_requested_size()) [[likely]]
+ __detail::__merge_adaptive
+ (__first, __middle, __last, __len1, __len2, __buf.begin(), __comp_proj);
+ else if (__buf.begin() == 0) [[unlikely]]
+ __detail::__merge_without_buffer
+ (__first, __middle, __last, __len1, __len2, __comp_proj);
+ else
+ __detail::__merge_adaptive_resize
+ (__first, __middle, __last, __len1, __len2, __buf.begin(),
+ _DistanceType(__buf.size()), __comp_proj);
+#else
+ __detail::__merge_without_buffer
+ (__first, __middle, __last, __len1, __len2, __comp_proj);
+#endif
+ return __last;
+ }
}
template<bidirectional_range _Range,
diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h
index dde1649..c09f729 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -119,9 +119,9 @@ namespace ranges
if constexpr (is_array_v<remove_reference_t<_Tp>>)
return true;
else if constexpr (__member_begin<_Tp>)
- return noexcept(__decay_copy(std::declval<_Tp&>().begin()));
+ return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().begin()));
else
- return noexcept(__decay_copy(begin(std::declval<_Tp&>())));
+ return noexcept(_GLIBCXX_AUTO_CAST(begin(std::declval<_Tp&>())));
}
public:
@@ -146,7 +146,7 @@ namespace ranges
template<typename _Tp>
concept __member_end = requires(_Tp& __t)
{
- { __decay_copy(__t.end()) } -> sentinel_for<__range_iter_t<_Tp>>;
+ { _GLIBCXX_AUTO_CAST(__t.end()) } -> sentinel_for<__range_iter_t<_Tp>>;
};
// Poison pill so that unqualified lookup doesn't find std::end.
@@ -156,7 +156,7 @@ namespace ranges
concept __adl_end = __class_or_enum<remove_reference_t<_Tp>>
&& requires(_Tp& __t)
{
- { __decay_copy(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
+ { _GLIBCXX_AUTO_CAST(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
};
struct _End
@@ -169,9 +169,9 @@ namespace ranges
if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
return true;
else if constexpr (__member_end<_Tp>)
- return noexcept(__decay_copy(std::declval<_Tp&>().end()));
+ return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().end()));
else
- return noexcept(__decay_copy(end(std::declval<_Tp&>())));
+ return noexcept(_GLIBCXX_AUTO_CAST(end(std::declval<_Tp&>())));
}
public:
@@ -196,7 +196,7 @@ namespace ranges
template<typename _Tp>
concept __member_rbegin = requires(_Tp& __t)
{
- { __decay_copy(__t.rbegin()) } -> input_or_output_iterator;
+ { _GLIBCXX_AUTO_CAST(__t.rbegin()) } -> input_or_output_iterator;
};
void rbegin() = delete;
@@ -205,7 +205,7 @@ namespace ranges
concept __adl_rbegin = __class_or_enum<remove_reference_t<_Tp>>
&& requires(_Tp& __t)
{
- { __decay_copy(rbegin(__t)) } -> input_or_output_iterator;
+ { _GLIBCXX_AUTO_CAST(rbegin(__t)) } -> input_or_output_iterator;
};
template<typename _Tp>
@@ -223,9 +223,9 @@ namespace ranges
_S_noexcept()
{
if constexpr (__member_rbegin<_Tp>)
- return noexcept(__decay_copy(std::declval<_Tp&>().rbegin()));
+ return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().rbegin()));
else if constexpr (__adl_rbegin<_Tp>)
- return noexcept(__decay_copy(rbegin(std::declval<_Tp&>())));
+ return noexcept(_GLIBCXX_AUTO_CAST(rbegin(std::declval<_Tp&>())));
else
{
if constexpr (noexcept(_End{}(std::declval<_Tp&>())))
@@ -258,7 +258,7 @@ namespace ranges
template<typename _Tp>
concept __member_rend = requires(_Tp& __t)
{
- { __decay_copy(__t.rend()) }
+ { _GLIBCXX_AUTO_CAST(__t.rend()) }
-> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
};
@@ -268,7 +268,7 @@ namespace ranges
concept __adl_rend = __class_or_enum<remove_reference_t<_Tp>>
&& requires(_Tp& __t)
{
- { __decay_copy(rend(__t)) }
+ { _GLIBCXX_AUTO_CAST(rend(__t)) }
-> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
};
@@ -280,9 +280,9 @@ namespace ranges
_S_noexcept()
{
if constexpr (__member_rend<_Tp>)
- return noexcept(__decay_copy(std::declval<_Tp&>().rend()));
+ return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().rend()));
else if constexpr (__adl_rend<_Tp>)
- return noexcept(__decay_copy(rend(std::declval<_Tp&>())));
+ return noexcept(_GLIBCXX_AUTO_CAST(rend(std::declval<_Tp&>())));
else
{
if constexpr (noexcept(_Begin{}(std::declval<_Tp&>())))
@@ -316,7 +316,7 @@ namespace ranges
concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>>
&& requires(_Tp& __t)
{
- { __decay_copy(__t.size()) } -> __detail::__is_integer_like;
+ { _GLIBCXX_AUTO_CAST(__t.size()) } -> __detail::__is_integer_like;
};
void size() = delete;
@@ -326,7 +326,7 @@ namespace ranges
&& !disable_sized_range<remove_cvref_t<_Tp>>
&& requires(_Tp& __t)
{
- { __decay_copy(size(__t)) } -> __detail::__is_integer_like;
+ { _GLIBCXX_AUTO_CAST(size(__t)) } -> __detail::__is_integer_like;
};
template<typename _Tp>
@@ -351,9 +351,9 @@ namespace ranges
if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
return true;
else if constexpr (__member_size<_Tp>)
- return noexcept(__decay_copy(std::declval<_Tp&>().size()));
+ return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().size()));
else if constexpr (__adl_size<_Tp>)
- return noexcept(__decay_copy(size(std::declval<_Tp&>())));
+ return noexcept(_GLIBCXX_AUTO_CAST(size(std::declval<_Tp&>())));
else if constexpr (__sentinel_size<_Tp>)
return noexcept(_End{}(std::declval<_Tp&>())
- _Begin{}(std::declval<_Tp&>()));
@@ -463,7 +463,7 @@ namespace ranges
template<typename _Tp>
concept __member_data = requires(_Tp& __t)
{
- { __decay_copy(__t.data()) } -> __pointer_to_object;
+ { _GLIBCXX_AUTO_CAST(__t.data()) } -> __pointer_to_object;
};
template<typename _Tp>
@@ -477,7 +477,7 @@ namespace ranges
_S_noexcept()
{
if constexpr (__member_data<_Tp>)
- return noexcept(__decay_copy(std::declval<_Tp&>().data()));
+ return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().data()));
else
return noexcept(_Begin{}(std::declval<_Tp&>()));
}
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index d8f9bd8..82871ce 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -34,231 +34,269 @@
#pragma GCC system_header
#endif
+#include <bits/version.h>
+
+#ifdef __glibcxx_semaphore // C++ >= 20 && hosted && atomic_wait
#include <bits/atomic_base.h>
#include <bits/chrono.h>
-#if __glibcxx_atomic_wait
#include <bits/atomic_timed_wait.h>
#include <ext/numeric_traits.h>
-#endif // __cpp_lib_atomic_wait
-
-#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
-# include <cerrno> // errno, EINTR, EAGAIN etc.
-# include <limits.h> // SEM_VALUE_MAX
-# include <semaphore.h> // sem_t, sem_init, sem_wait, sem_post etc.
-#elif defined(_GLIBCXX_USE_POSIX_SEMAPHORE)
-# warning "POSIX semaphore not available, ignoring _GLIBCXX_USE_POSIX_SEMAPHORE"
-# undef _GLIBCXX_USE_POSIX_SEMAPHORE
-#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
-#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
- struct __platform_semaphore
+ struct __semaphore_impl
{
- using __clock_t = chrono::system_clock;
-#ifdef SEM_VALUE_MAX
- static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
-#else
- static constexpr ptrdiff_t _S_max = _POSIX_SEM_VALUE_MAX;
-#endif
+ using __count_type = ptrdiff_t;
- explicit __platform_semaphore(ptrdiff_t __count) noexcept
- {
- sem_init(&_M_semaphore, 0, __count);
- }
+ static constexpr ptrdiff_t _S_max
+ = __gnu_cxx::__int_traits<__count_type>::__max;
- __platform_semaphore(const __platform_semaphore&) = delete;
- __platform_semaphore& operator=(const __platform_semaphore&) = delete;
+ constexpr explicit
+ __semaphore_impl(__count_type __count) noexcept
+ : _M_counter(__count)
+ { }
- ~__platform_semaphore()
- { sem_destroy(&_M_semaphore); }
+ __semaphore_impl(const __semaphore_impl&) = delete;
+ __semaphore_impl& operator=(const __semaphore_impl&) = delete;
- _GLIBCXX_ALWAYS_INLINE void
- _M_acquire() noexcept
- {
- while (sem_wait(&_M_semaphore))
- if (errno != EINTR)
- std::__terminate();
- }
+ // Load the current counter value.
+ _GLIBCXX_ALWAYS_INLINE __count_type
+ _M_get_current() const noexcept
+ { return __atomic_impl::load(&_M_counter, memory_order::acquire); }
+ // Try to acquire the semaphore (i.e. decrement the counter).
+ // Returns false if the current counter is zero, or if another thread
+ // changes the value first. In the latter case, __cur is set to the new
+ // value.
_GLIBCXX_ALWAYS_INLINE bool
- _M_try_acquire() noexcept
+ _M_do_try_acquire(__count_type& __cur) noexcept
{
- while (sem_trywait(&_M_semaphore))
- {
- if (errno == EAGAIN) // already locked
- return false;
- else if (errno != EINTR)
- std::__terminate();
- // else got EINTR so retry
- }
- return true;
+ if (__cur == 0)
+ return false; // Cannot decrement when it's already zero.
+
+ return __atomic_impl::compare_exchange_strong(&_M_counter,
+ __cur, __cur - 1,
+ memory_order::acquire,
+ memory_order::relaxed);
}
- _GLIBCXX_ALWAYS_INLINE void
- _M_release(ptrdiff_t __update) noexcept
+ // Keep trying to acquire the semaphore in a loop until it succeeds.
+ void
+ _M_acquire() noexcept
{
- for(; __update != 0; --__update)
- if (sem_post(&_M_semaphore))
- std::__terminate();
+ auto __vfn = [this]{ return _M_get_current(); };
+ _Available __is_available{__vfn()};
+ while (!_M_do_try_acquire(__is_available._M_val))
+ if (!__is_available())
+ std::__atomic_wait_address(&_M_counter, __is_available, __vfn, true);
}
+ // Try to acquire the semaphore, retrying a small number of times
+ // in case of contention.
bool
- _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime)
- noexcept
+ _M_try_acquire() noexcept
{
- auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
- auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
-
- struct timespec __ts =
- {
- static_cast<std::time_t>(__s.time_since_epoch().count()),
- static_cast<long>(__ns.count())
- };
-
- while (sem_timedwait(&_M_semaphore, &__ts))
- {
- if (errno == ETIMEDOUT)
- return false;
- else if (errno != EINTR)
- std::__terminate();
- }
- return true;
+ // The fastest implementation of this function is just _M_do_try_acquire
+ // but that can fail under contention even when _M_count > 0.
+ // Using _M_try_acquire_for(0ns) will retry a few times in a loop.
+ return _M_try_acquire_for(__detail::__wait_clock_t::duration{});
}
template<typename _Clock, typename _Duration>
bool
- _M_try_acquire_until(const chrono::time_point<_Clock,
- _Duration>& __atime) noexcept
+ _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
{
- if constexpr (std::is_same_v<__clock_t, _Clock>)
- {
- using _Dur = __clock_t::duration;
- return _M_try_acquire_until_impl(chrono::ceil<_Dur>(__atime));
- }
- else
- {
- // TODO: if _Clock is monotonic_clock we could use
- // sem_clockwait with CLOCK_MONOTONIC.
-
- const typename _Clock::time_point __c_entry = _Clock::now();
- const auto __s_entry = __clock_t::now();
- const auto __delta = __atime - __c_entry;
- const auto __s_atime = __s_entry + __delta;
- if (_M_try_acquire_until_impl(__s_atime))
- return true;
-
- // We got a timeout when measured against __clock_t but
- // we need to check against the caller-supplied clock
- // to tell whether we should return a timeout.
- return (_Clock::now() < __atime);
- }
+ auto __vfn = [this]{ return _M_get_current(); };
+ _Available __is_available{__vfn()};
+ while (!_M_do_try_acquire(__is_available._M_val))
+ if (!__is_available())
+ if (!std::__atomic_wait_address_until(&_M_counter, __is_available,
+ __vfn, __atime, true))
+ return false; // timed out
+ return true;
}
template<typename _Rep, typename _Period>
- _GLIBCXX_ALWAYS_INLINE bool
- _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
- noexcept
- { return _M_try_acquire_until(__clock_t::now() + __rtime); }
+ bool
+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
+ {
+ auto __vfn = [this]{ return _M_get_current(); };
+ _Available __is_available{__vfn()};
+ while (!_M_do_try_acquire(__is_available._M_val))
+ if (!__is_available())
+ if (!std::__atomic_wait_address_for(&_M_counter, __is_available,
+ __vfn, __rtime, true))
+ return false; // timed out
+ return true;
+ }
+
+ _GLIBCXX_ALWAYS_INLINE ptrdiff_t
+ _M_release(ptrdiff_t __update) noexcept
+ {
+ auto __old = __atomic_impl::fetch_add(&_M_counter, __update,
+ memory_order::release);
+ if (__old == 0 && __update > 0)
+ __atomic_notify_address(&_M_counter, true, true);
+ return __old;
+ }
private:
- sem_t _M_semaphore;
+ struct _Available
+ {
+ __count_type _M_val; // Cache of the last value loaded from _M_counter.
+
+ // Returns true if the cached value is non-zero and so it should be
+ // possible to acquire the semaphore.
+ bool operator()() const noexcept { return _M_val > 0; }
+
+ // Argument should be the latest value of the counter.
+ // Returns true (and caches the value) if it's non-zero, meaning it
+ // should be possible to acquire the semaphore. Returns false otherwise.
+ bool operator()(__count_type __cur) noexcept
+ {
+ if (__cur == 0)
+ return false;
+ _M_val = __cur;
+ return true;
+ }
+ };
+
+ alignas(__atomic_ref<__count_type>::required_alignment)
+ __count_type _M_counter;
};
-#endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE
-#if __glibcxx_atomic_wait
- struct __atomic_semaphore
+ // Optimized specialization using __platform_wait (if available)
+ template<bool _Binary>
+ struct __platform_semaphore_impl
{
- static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<int>::__max;
- explicit __atomic_semaphore(__detail::__platform_wait_t __count) noexcept
- : _M_counter(__count)
+ using __count_type = __detail::__platform_wait_t;
+
+ static constexpr ptrdiff_t _S_max
+ = _Binary ? 1 : __gnu_cxx::__int_traits<__count_type>::__max;
+
+ constexpr explicit
+ __platform_semaphore_impl(__count_type __count) noexcept
+ : _M_counter(__count)
+ { }
+
+ __platform_semaphore_impl(__platform_semaphore_impl&) = delete;
+ __platform_semaphore_impl& operator=(const __platform_semaphore_impl&) = delete;
+
+ // Load the current counter value.
+ _GLIBCXX_ALWAYS_INLINE __count_type
+ _M_get_current() const noexcept
{
- __glibcxx_assert(__count >= 0 && __count <= _S_max);
+ if constexpr (_Binary)
+ return 1; // Not necessarily true, but optimistically assume it is.
+ else
+ return __atomic_impl::load(&_M_counter, memory_order::acquire);
}
- __atomic_semaphore(const __atomic_semaphore&) = delete;
- __atomic_semaphore& operator=(const __atomic_semaphore&) = delete;
-
- static _GLIBCXX_ALWAYS_INLINE bool
- _S_do_try_acquire(__detail::__platform_wait_t* __counter) noexcept
+ // Try to acquire the semaphore (i.e. decrement the counter).
+ // Returns false if the current counter is zero, or if another thread
+ // changes the value first. In the latter case, __cur is set to the new
+ // value.
+ _GLIBCXX_ALWAYS_INLINE bool
+ _M_do_try_acquire(__count_type& __cur) noexcept
{
- auto __old = __atomic_impl::load(__counter, memory_order::acquire);
- if (__old == 0)
- return false;
+ if (__cur == 0)
+ return false; // Cannot decrement when it's already zero.
- return __atomic_impl::compare_exchange_strong(__counter,
- __old, __old - 1,
+ return __atomic_impl::compare_exchange_strong(&_M_counter,
+ __cur, __cur - 1,
memory_order::acquire,
memory_order::relaxed);
}
- _GLIBCXX_ALWAYS_INLINE void
+ // Keep trying to acquire the semaphore in a loop until it succeeds.
+ void
_M_acquire() noexcept
{
- auto const __pred =
- [this] { return _S_do_try_acquire(&this->_M_counter); };
- std::__atomic_wait_address_bare(&_M_counter, __pred);
+ auto __val = _M_get_current();
+ while (!_M_do_try_acquire(__val))
+ if (__val == 0)
+ {
+ std::__atomic_wait_address_v(&_M_counter, __val, __ATOMIC_ACQUIRE,
+ true);
+ __val = _M_get_current();
+ }
}
+ // Try to acquire the semaphore.
bool
_M_try_acquire() noexcept
{
- auto const __pred =
- [this] { return _S_do_try_acquire(&this->_M_counter); };
- return std::__detail::__atomic_spin(__pred);
+ if constexpr (_Binary)
+ {
+ __count_type __val = 1;
+ // Do not expect much contention on binary semaphore, only try once.
+ return _M_do_try_acquire(__val);
+ }
+ else
+ // Fastest implementation of this function is just _M_do_try_acquire
+ // but that can fail under contention even when _M_count > 0.
+ // Using _M_try_acquire_for(0ns) will retry a few times in a loop.
+ return _M_try_acquire_for(__detail::__wait_clock_t::duration{});
}
template<typename _Clock, typename _Duration>
- _GLIBCXX_ALWAYS_INLINE bool
- _M_try_acquire_until(const chrono::time_point<_Clock,
- _Duration>& __atime) noexcept
+ bool
+ _M_try_acquire_until(const chrono::time_point<_Clock, _Duration>& __atime) noexcept
{
- auto const __pred =
- [this] { return _S_do_try_acquire(&this->_M_counter); };
-
- return __atomic_wait_address_until_bare(&_M_counter, __pred, __atime);
+ auto __val = _M_get_current();
+ while (!_M_do_try_acquire(__val))
+ if (__val == 0)
+ {
+ if (!std::__atomic_wait_address_until_v(&_M_counter, 0,
+ __ATOMIC_ACQUIRE,
+ __atime, true))
+ return false; // timed out
+ __val = _M_get_current();
+ }
+ return true;
}
template<typename _Rep, typename _Period>
- _GLIBCXX_ALWAYS_INLINE bool
- _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime)
- noexcept
+ bool
+ _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) noexcept
{
- auto const __pred =
- [this] { return _S_do_try_acquire(&this->_M_counter); };
-
- return __atomic_wait_address_for_bare(&_M_counter, __pred, __rtime);
+ auto __val = _M_get_current();
+ while (!_M_do_try_acquire(__val))
+ if (__val == 0)
+ {
+ if (!std::__atomic_wait_address_for_v(&_M_counter, 0,
+ __ATOMIC_ACQUIRE,
+ __rtime, true))
+ return false; // timed out
+ __val = _M_get_current();
+ }
+ return true;
}
- _GLIBCXX_ALWAYS_INLINE void
+ _GLIBCXX_ALWAYS_INLINE ptrdiff_t
_M_release(ptrdiff_t __update) noexcept
{
- if (0 < __atomic_impl::fetch_add(&_M_counter, __update, memory_order_release))
- return;
- if (__update > 1)
- __atomic_notify_address_bare(&_M_counter, true);
- else
- __atomic_notify_address_bare(&_M_counter, true);
-// FIXME - Figure out why this does not wake a waiting thread
-// __atomic_notify_address_bare(&_M_counter, false);
+ auto __old = __atomic_impl::fetch_add(&_M_counter, __update,
+ memory_order::release);
+ if (__old == 0 && __update > 0)
+ __atomic_notify_address(&_M_counter, true, true);
+ return __old;
}
- private:
- alignas(__detail::__platform_wait_alignment)
- __detail::__platform_wait_t _M_counter;
+ protected:
+ alignas(__detail::__platform_wait_alignment) __count_type _M_counter;
};
-#endif // __cpp_lib_atomic_wait
-
-// Note: the _GLIBCXX_USE_POSIX_SEMAPHORE macro can be used to force the
-// use of Posix semaphores (sem_t). Doing so however, alters the ABI.
-#if defined __glibcxx_atomic_wait && !_GLIBCXX_USE_POSIX_SEMAPHORE
- using __semaphore_impl = __atomic_semaphore;
-#elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
- using __semaphore_impl = __platform_semaphore;
-#endif
+
+ template<ptrdiff_t _Max, typename _Tp = __detail::__platform_wait_t>
+ using _Semaphore_impl
+ = __conditional_t<__platform_wait_uses_type<_Tp>
+ && _Max <= __gnu_cxx::__int_traits<_Tp>::__max,
+ __platform_semaphore_impl<(_Max <= 1)>,
+ __semaphore_impl>;
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
+#endif // __glibcxx_semaphore
#endif // _GLIBCXX_SEMAPHORE_BASE_H
diff --git a/libstdc++-v3/include/bits/std_abs.h b/libstdc++-v3/include/bits/std_abs.h
index 35ec4d3..3d805e6 100644
--- a/libstdc++-v3/include/bits/std_abs.h
+++ b/libstdc++-v3/include/bits/std_abs.h
@@ -103,6 +103,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
abs(__GLIBCXX_TYPE_INT_N_3 __x) { return __x >= 0 ? __x : -__x; }
#endif
+#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
+ // In strict modes __GLIBCXX_TYPE_INT_N_0 is not defined for __int128,
+ // but we want to always define std::abs(__int128).
+ __extension__ inline _GLIBCXX_CONSTEXPR __int128
+ abs(__int128 __x) { return __x >= 0 ? __x : -__x; }
+#endif
+
#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
constexpr _Float16
abs(_Float16 __x)
@@ -137,7 +144,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __gnu_cxx::__bfloat16_t(__builtin_fabsf(__x)); }
#endif
-#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128)
+#if defined(_GLIBCXX_USE_FLOAT128)
__extension__ inline _GLIBCXX_CONSTEXPR
__float128
abs(__float128 __x)
diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h
index 71ead10..3f4674d 100644
--- a/libstdc++-v3/include/bits/stl_algo.h
+++ b/libstdc++-v3/include/bits/stl_algo.h
@@ -918,62 +918,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__gnu_cxx::__ops::__iter_comp_iter(__binary_pred));
}
- /**
- * This is an uglified
- * unique_copy(_InputIterator, _InputIterator, _OutputIterator,
- * _BinaryPredicate)
- * overloaded for forward iterators and output iterator as result.
- */
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4269. unique_copy passes arguments to its predicate backwards
+
+ // Implementation of std::unique_copy for forward iterators.
+ // This case is easy, just compare *i with *(i-1).
template<typename _ForwardIterator, typename _OutputIterator,
typename _BinaryPredicate>
_GLIBCXX20_CONSTEXPR
_OutputIterator
__unique_copy(_ForwardIterator __first, _ForwardIterator __last,
_OutputIterator __result, _BinaryPredicate __binary_pred,
- forward_iterator_tag, output_iterator_tag)
+ forward_iterator_tag)
{
- // concept requirements -- iterators already checked
- __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate,
- typename iterator_traits<_ForwardIterator>::value_type,
- typename iterator_traits<_ForwardIterator>::value_type>)
-
- _ForwardIterator __next = __first;
+ _ForwardIterator __prev = __first;
*__result = *__first;
- while (++__next != __last)
- if (!__binary_pred(__first, __next))
+ while (++__first != __last)
+ if (!__binary_pred(__prev, __first))
{
- __first = __next;
*++__result = *__first;
+ __prev = __first;
}
return ++__result;
}
- /**
- * This is an uglified
- * unique_copy(_InputIterator, _InputIterator, _OutputIterator,
- * _BinaryPredicate)
- * overloaded for input iterators and output iterator as result.
- */
+ // Implementation of std::unique_copy for non-forward iterators,
+ // where we cannot compare with elements written to the output.
template<typename _InputIterator, typename _OutputIterator,
typename _BinaryPredicate>
_GLIBCXX20_CONSTEXPR
_OutputIterator
- __unique_copy(_InputIterator __first, _InputIterator __last,
- _OutputIterator __result, _BinaryPredicate __binary_pred,
- input_iterator_tag, output_iterator_tag)
+ __unique_copy_1(_InputIterator __first, _InputIterator __last,
+ _OutputIterator __result, _BinaryPredicate __binary_pred,
+ __false_type)
{
- // concept requirements -- iterators already checked
- __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate,
- typename iterator_traits<_InputIterator>::value_type,
- typename iterator_traits<_InputIterator>::value_type>)
-
- typename iterator_traits<_InputIterator>::value_type __value = *__first;
- __decltype(__gnu_cxx::__ops::__iter_comp_val(__binary_pred))
- __rebound_pred
- = __gnu_cxx::__ops::__iter_comp_val(__binary_pred);
+ typedef typename iterator_traits<_InputIterator>::value_type _Val;
+ _Val __value = *__first;
*__result = __value;
while (++__first != __last)
- if (!__rebound_pred(__first, __value))
+ if (!__binary_pred(std::__addressof(__value), __first))
{
__value = *__first;
*++__result = __value;
@@ -981,24 +964,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return ++__result;
}
- /**
- * This is an uglified
- * unique_copy(_InputIterator, _InputIterator, _OutputIterator,
- * _BinaryPredicate)
- * overloaded for input iterators and forward iterator as result.
- */
+ // Implementation of std::unique_copy for non-forward iterators,
+ // where we can compare with the last element written to the output.
template<typename _InputIterator, typename _ForwardIterator,
typename _BinaryPredicate>
- _GLIBCXX20_CONSTEXPR
_ForwardIterator
- __unique_copy(_InputIterator __first, _InputIterator __last,
- _ForwardIterator __result, _BinaryPredicate __binary_pred,
- input_iterator_tag, forward_iterator_tag)
+ __unique_copy_1(_InputIterator __first, _InputIterator __last,
+ _ForwardIterator __result, _BinaryPredicate __binary_pred,
+ __true_type)
{
- // concept requirements -- iterators already checked
- __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate,
- typename iterator_traits<_ForwardIterator>::value_type,
- typename iterator_traits<_InputIterator>::value_type>)
*__result = *__first;
while (++__first != __last)
if (!__binary_pred(__result, __first))
@@ -1006,6 +980,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return ++__result;
}
+ // Implementation of std::unique_copy for non-forward iterators.
+ // We cannot compare *i to *(i-1) so we need to either make a copy
+ // or compare with the last element written to the output range.
+ template<typename _InputIterator, typename _OutputIterator,
+ typename _BinaryPredicate>
+ _GLIBCXX20_CONSTEXPR
+ _OutputIterator
+ __unique_copy(_InputIterator __first, _InputIterator __last,
+ _OutputIterator __result, _BinaryPredicate __binary_pred,
+ input_iterator_tag)
+ {
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2439. unique_copy() sometimes can't fall back to reading its output
+ typedef iterator_traits<_InputIterator> _InItTraits;
+ typedef iterator_traits<_OutputIterator> _OutItTraits;
+ typedef typename _OutItTraits::iterator_category _Cat;
+ const bool __output_is_fwd = __is_base_of(forward_iterator_tag, _Cat);
+ const bool __same_type = __is_same(typename _OutItTraits::value_type,
+ typename _InItTraits::value_type);
+ typedef __truth_type<__output_is_fwd && __same_type> __cmp_with_output;
+ return std::__unique_copy_1(__first, __last, __result, __binary_pred,
+ typename __cmp_with_output::__type());
+ }
+
+
/**
* This is an uglified reverse(_BidirectionalIterator,
* _BidirectionalIterator)
@@ -2512,7 +2511,7 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
// [first,middle) and [middle,last).
_TmpBuf __buf(__first, std::min(__len1, __len2));
- if (__builtin_expect(__buf.size() == __buf.requested_size(), true))
+ if (__builtin_expect(__buf.size() == __buf._M_requested_size(), true))
std::__merge_adaptive
(__first, __middle, __last, __len1, __len2, __buf.begin(), __comp);
else if (__builtin_expect(__buf.begin() == 0, false))
@@ -4470,8 +4469,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
return __result;
return std::__unique_copy(__first, __last, __result,
__gnu_cxx::__ops::__iter_equal_to_iter(),
- std::__iterator_category(__first),
- std::__iterator_category(__result));
+ std::__iterator_category(__first));
}
/**
@@ -4505,13 +4503,15 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
__glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator,
typename iterator_traits<_InputIterator>::value_type>)
__glibcxx_requires_valid_range(__first, __last);
+ __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate,
+ typename iterator_traits<_InputIterator>::value_type,
+ typename iterator_traits<_InputIterator>::value_type>)
if (__first == __last)
return __result;
return std::__unique_copy(__first, __last, __result,
__gnu_cxx::__ops::__iter_comp_iter(__binary_pred),
- std::__iterator_category(__first),
- std::__iterator_category(__result));
+ std::__iterator_category(__first));
}
#if __cplusplus <= 201103L || _GLIBCXX_USE_DEPRECATED
@@ -5024,7 +5024,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
// so the buffer only needs to fit half the range at once.
_TmpBuf __buf(__first, (__last - __first + 1) / 2);
- if (__builtin_expect(__buf.requested_size() == __buf.size(), true))
+ if (__builtin_expect(__buf._M_requested_size() == __buf.size(), true))
std::__stable_sort_adaptive(__first,
__first + _DistanceType(__buf.size()),
__last, __buf.begin(), __comp);
diff --git a/libstdc++-v3/include/bits/stl_construct.h b/libstdc++-v3/include/bits/stl_construct.h
index 23b8fb7..217a041 100644
--- a/libstdc++-v3/include/bits/stl_construct.h
+++ b/libstdc++-v3/include/bits/stl_construct.h
@@ -82,7 +82,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if constexpr (__cplusplus > 201703L && is_array_v<_Tp>)
{
for (auto& __x : *__location)
- std::destroy_at(std::__addressof(__x));
+ std::destroy_at(std::addressof(__x));
}
else
__location->~_Tp();
@@ -123,7 +123,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Construct(_Tp* __p, _Args&&... __args)
{
#if __cpp_constexpr_dynamic_alloc // >= C++20
- if (std::__is_constant_evaluated())
+ if (std::is_constant_evaluated())
{
// Allow std::_Construct to be used in constant expressions.
std::construct_at(__p, std::forward<_Args>(__args)...);
@@ -181,6 +181,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
for (; __first != __last; ++__first)
std::_Destroy(std::__addressof(*__first));
}
+
+ template<typename _ForwardIterator, typename _Size>
+ static _GLIBCXX20_CONSTEXPR _ForwardIterator
+ __destroy_n(_ForwardIterator __first, _Size __count)
+ {
+ for (; __count > 0; (void)++__first, --__count)
+ std::_Destroy(std::__addressof(*__first));
+ return __first;
+ }
};
template<>
@@ -189,6 +198,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _ForwardIterator>
static void
__destroy(_ForwardIterator, _ForwardIterator) { }
+
+ template<typename _ForwardIterator, typename _Size>
+ static _ForwardIterator
+ __destroy_n(_ForwardIterator __first, _Size __count)
+ {
+ std::advance(__first, __count);
+ return __first;
+ }
};
#endif
@@ -204,16 +221,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef typename iterator_traits<_ForwardIterator>::value_type
_Value_type;
#if __cplusplus >= 201103L
- // A deleted destructor is trivial, this ensures we reject such types:
- static_assert(is_destructible<_Value_type>::value,
- "value type is destructible");
- if constexpr (!__has_trivial_destructor(_Value_type))
+ if constexpr (!is_trivially_destructible<_Value_type>::value)
for (; __first != __last; ++__first)
- std::_Destroy(std::__addressof(*__first));
+ std::_Destroy(std::addressof(*__first));
#if __cpp_constexpr_dynamic_alloc // >= C++20
- else if (std::__is_constant_evaluated())
+ else if (std::is_constant_evaluated())
for (; __first != __last; ++__first)
- std::destroy_at(std::__addressof(*__first));
+ std::destroy_at(std::addressof(*__first));
#endif
#else
std::_Destroy_aux<__has_trivial_destructor(_Value_type)>::
@@ -221,33 +235,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
}
-#if __cplusplus < 201103L
- template<bool>
- struct _Destroy_n_aux
- {
- template<typename _ForwardIterator, typename _Size>
- static _GLIBCXX20_CONSTEXPR _ForwardIterator
- __destroy_n(_ForwardIterator __first, _Size __count)
- {
- for (; __count > 0; (void)++__first, --__count)
- std::_Destroy(std::__addressof(*__first));
- return __first;
- }
- };
-
- template<>
- struct _Destroy_n_aux<true>
- {
- template<typename _ForwardIterator, typename _Size>
- static _ForwardIterator
- __destroy_n(_ForwardIterator __first, _Size __count)
- {
- std::advance(__first, __count);
- return __first;
- }
- };
-#endif
-
/**
* Destroy a range of objects. If the value_type of the object has
* a trivial destructor, the compiler should optimize all of this
@@ -260,22 +247,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef typename iterator_traits<_ForwardIterator>::value_type
_Value_type;
#if __cplusplus >= 201103L
- // A deleted destructor is trivial, this ensures we reject such types:
- static_assert(is_destructible<_Value_type>::value,
- "value type is destructible");
- if constexpr (!__has_trivial_destructor(_Value_type))
+ if constexpr (!is_trivially_destructible<_Value_type>::value)
for (; __count > 0; (void)++__first, --__count)
- std::_Destroy(std::__addressof(*__first));
+ std::_Destroy(std::addressof(*__first));
#if __cpp_constexpr_dynamic_alloc // >= C++20
- else if (std::__is_constant_evaluated())
+ else if (std::is_constant_evaluated())
for (; __count > 0; (void)++__first, --__count)
- std::destroy_at(std::__addressof(*__first));
+ std::destroy_at(std::addressof(*__first));
#endif
else
std::advance(__first, __count);
return __first;
#else
- return std::_Destroy_n_aux<__has_trivial_destructor(_Value_type)>::
+ return std::_Destroy_aux<__has_trivial_destructor(_Value_type)>::
__destroy_n(__first, __count);
#endif
}
diff --git a/libstdc++-v3/include/bits/stl_deque.h b/libstdc++-v3/include/bits/stl_deque.h
index 8d8ee57..7055641 100644
--- a/libstdc++-v3/include/bits/stl_deque.h
+++ b/libstdc++-v3/include/bits/stl_deque.h
@@ -1331,7 +1331,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{
size_type __sz = this->_M_impl._M_finish - this->_M_impl._M_start;
if (__sz > max_size ())
- __builtin_unreachable ();
+ __builtin_unreachable();
return __sz;
}
diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h
index bed7295..478a98f 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -2511,17 +2511,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
[[nodiscard]]
friend constexpr iter_difference_t<_It2>
operator-(const counted_iterator& __x,
- const counted_iterator<_It2>& __y)
+ const counted_iterator<_It2>& __y) noexcept
{ return __y._M_length - __x._M_length; }
[[nodiscard]]
friend constexpr iter_difference_t<_It>
- operator-(const counted_iterator& __x, default_sentinel_t)
+ operator-(const counted_iterator& __x, default_sentinel_t) noexcept
{ return -__x._M_length; }
[[nodiscard]]
friend constexpr iter_difference_t<_It>
- operator-(default_sentinel_t, const counted_iterator& __y)
+ operator-(default_sentinel_t, const counted_iterator& __y) noexcept
{ return __y._M_length; }
constexpr counted_iterator&
@@ -2548,19 +2548,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
[[nodiscard]]
friend constexpr bool
operator==(const counted_iterator& __x,
- const counted_iterator<_It2>& __y)
+ const counted_iterator<_It2>& __y) noexcept
{ return __x._M_length == __y._M_length; }
[[nodiscard]]
friend constexpr bool
- operator==(const counted_iterator& __x, default_sentinel_t)
+ operator==(const counted_iterator& __x, default_sentinel_t) noexcept
{ return __x._M_length == 0; }
template<common_with<_It> _It2>
[[nodiscard]]
friend constexpr strong_ordering
operator<=>(const counted_iterator& __x,
- const counted_iterator<_It2>& __y)
+ const counted_iterator<_It2>& __y) noexcept
{ return __y._M_length <=> __x._M_length; }
[[nodiscard]]
diff --git a/libstdc++-v3/include/bits/stl_tempbuf.h b/libstdc++-v3/include/bits/stl_tempbuf.h
index 7a7619e..8cc7b11 100644
--- a/libstdc++-v3/include/bits/stl_tempbuf.h
+++ b/libstdc++-v3/include/bits/stl_tempbuf.h
@@ -227,7 +227,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Returns the size requested by the constructor; may be >size().
size_type
- requested_size() const
+ _M_requested_size() const
{ return _M_original_len; }
/// As per Table mumble.
diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h
index b1428db..f4b26cc 100644
--- a/libstdc++-v3/include/bits/stl_uninitialized.h
+++ b/libstdc++-v3/include/bits/stl_uninitialized.h
@@ -118,7 +118,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
~_UninitDestroyGuard()
{
if (__builtin_expect(_M_cur != 0, 0))
+#if __cplusplus == 201703L
+ // std::uninitialized_{value,default}{,_n} can construct array types,
+ // but std::_Destroy cannot handle them until C++20 (PR 120397).
+ _S_destroy(_M_first, *_M_cur);
+#else
std::_Destroy(_M_first, *_M_cur);
+#endif
}
_GLIBCXX20_CONSTEXPR
@@ -129,6 +135,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
private:
_UninitDestroyGuard(const _UninitDestroyGuard&);
+
+#if __cplusplus == 201703L
+ template<typename _Iter>
+ static void
+ _S_destroy(_Iter __first, _Iter __last)
+ {
+ using _ValT = typename iterator_traits<_Iter>::value_type;
+ if constexpr (is_array<_ValT>::value)
+ for (; __first != __last; ++__first)
+ _S_destroy(*__first, *__first + extent<_ValT>::value);
+ else
+ std::_Destroy(__first, __last);
+ }
+#endif
};
// This is the default implementation of std::uninitialized_copy.
@@ -839,7 +859,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
_UninitDestroyGuard<_ForwardIterator> __guard(__first);
for (; __first != __last; ++__first)
- std::_Construct(std::__addressof(*__first));
+ std::_Construct(std::addressof(*__first));
__guard.release();
}
};
@@ -856,7 +876,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return;
typename iterator_traits<_ForwardIterator>::value_type* __val
- = std::__addressof(*__first);
+ = std::addressof(*__first);
std::_Construct(__val);
if (++__first != __last)
std::fill(__first, __last, *__val);
@@ -873,7 +893,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
_UninitDestroyGuard<_ForwardIterator> __guard(__first);
for (; __n > 0; --__n, (void) ++__first)
- std::_Construct(std::__addressof(*__first));
+ std::_Construct(std::addressof(*__first));
__guard.release();
return __first;
}
@@ -890,7 +910,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__n > 0)
{
typename iterator_traits<_ForwardIterator>::value_type* __val
- = std::__addressof(*__first);
+ = std::addressof(*__first);
std::_Construct(__val);
++__first;
__first = std::fill_n(__first, __n - 1, *__val);
@@ -955,7 +975,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__alloc);
typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
for (; __first != __last; ++__first)
- __traits::construct(__alloc, std::__addressof(*__first));
+ __traits::construct(__alloc, std::addressof(*__first));
__guard.release();
}
@@ -980,7 +1000,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__alloc);
typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
for (; __n > 0; --__n, (void) ++__first)
- __traits::construct(__alloc, std::__addressof(*__first));
+ __traits::construct(__alloc, std::addressof(*__first));
__guard.release();
return __first;
}
@@ -1007,7 +1027,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
_UninitDestroyGuard<_ForwardIterator> __guard(__first);
for (; __first != __last; ++__first)
- std::_Construct_novalue(std::__addressof(*__first));
+ std::_Construct_novalue(std::addressof(*__first));
__guard.release();
}
};
@@ -1033,7 +1053,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
_UninitDestroyGuard<_ForwardIterator> __guard(__first);
for (; __n > 0; --__n, (void) ++__first)
- std::_Construct_novalue(std::__addressof(*__first));
+ std::_Construct_novalue(std::addressof(*__first));
__guard.release();
return __first;
}
@@ -1089,7 +1109,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
_UninitDestroyGuard<_ForwardIterator> __guard(__result);
for (; __n > 0; --__n, (void) ++__first, ++__result)
- std::_Construct(std::__addressof(*__result), *__first);
+ std::_Construct(std::addressof(*__result), *__first);
__guard.release();
return __result;
}
@@ -1112,7 +1132,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
_UninitDestroyGuard<_ForwardIterator> __guard(__result);
for (; __n > 0; --__n, (void) ++__first, ++__result)
- std::_Construct(std::__addressof(*__result), *__first);
+ std::_Construct(std::addressof(*__result), *__first);
__guard.release();
return {__first, __result};
}
@@ -1276,11 +1296,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(noexcept(std::allocator_traits<_Allocator>::construct(__alloc,
__dest, std::move(*__orig)))
&& noexcept(std::allocator_traits<_Allocator>::destroy(
- __alloc, std::__addressof(*__orig))))
+ __alloc, std::addressof(*__orig))))
{
typedef std::allocator_traits<_Allocator> __traits;
__traits::construct(__alloc, __dest, std::move(*__orig));
- __traits::destroy(__alloc, std::__addressof(*__orig));
+ __traits::destroy(__alloc, std::addressof(*__orig));
}
// This class may be specialized for specific types.
@@ -1308,8 +1328,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"relocation is only possible for values of the same type");
_ForwardIterator __cur = __result;
for (; __first != __last; ++__first, (void)++__cur)
- std::__relocate_object_a(std::__addressof(*__cur),
- std::__addressof(*__first), __alloc);
+ std::__relocate_object_a(std::addressof(*__cur),
+ std::addressof(*__first), __alloc);
return __cur;
}
diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index 57680b7..f2c1bce 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -372,8 +372,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_GLIBCXX20_CONSTEXPR
~_Vector_base() _GLIBCXX_NOEXCEPT
{
- _M_deallocate(_M_impl._M_start,
- _M_impl._M_end_of_storage - _M_impl._M_start);
+ ptrdiff_t __n = _M_impl._M_end_of_storage - _M_impl._M_start;
+ if (__n < 0)
+ __builtin_unreachable();
+ _M_deallocate(_M_impl._M_start, size_t(__n));
}
public:
@@ -1106,7 +1108,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{
ptrdiff_t __dif = this->_M_impl._M_finish - this->_M_impl._M_start;
if (__dif < 0)
- __builtin_unreachable ();
+ __builtin_unreachable();
return size_type(__dif);
}
@@ -1198,7 +1200,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
ptrdiff_t __dif = this->_M_impl._M_end_of_storage
- this->_M_impl._M_start;
if (__dif < 0)
- __builtin_unreachable ();
+ __builtin_unreachable();
return size_type(__dif);
}
@@ -1969,8 +1971,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_M_range_initialize_n(_Iterator __first, _Sentinel __last,
size_type __n)
{
- pointer __start = this->_M_impl._M_start =
+ pointer __start =
this->_M_allocate(_S_check_init_len(__n, _M_get_Tp_allocator()));
+ this->_M_impl._M_start = this->_M_impl._M_finish = __start;
this->_M_impl._M_end_of_storage = __start + __n;
this->_M_impl._M_finish
= std::__uninitialized_copy_a(_GLIBCXX_MOVE(__first), __last,
diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h
index 6fa6b67..84d25e0 100644
--- a/libstdc++-v3/include/bits/utility.h
+++ b/libstdc++-v3/include/bits/utility.h
@@ -316,6 +316,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline constexpr sorted_equivalent_t sorted_equivalent{};
#endif
+#if __glibcxx_function_ref // >= C++26
+ template<auto>
+ struct nontype_t
+ {
+ explicit nontype_t() = default;
+ };
+
+ template<auto __val>
+ constexpr nontype_t<__val> nontype{};
+
+ template<typename>
+ inline constexpr bool __is_nontype_v = false;
+
+ template<auto __val>
+ inline constexpr bool __is_nontype_v<nontype_t<__val>> = true;
+#endif
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc
index e18f01a..70ead1d 100644
--- a/libstdc++-v3/include/bits/vector.tcc
+++ b/libstdc++-v3/include/bits/vector.tcc
@@ -466,7 +466,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{
const size_type __len = _M_check_len(1u, "vector::_M_realloc_insert");
if (__len <= 0)
- __builtin_unreachable ();
+ __builtin_unreachable();
pointer __old_start = this->_M_impl._M_start;
pointer __old_finish = this->_M_impl._M_finish;
const size_type __elems_before = __position - begin();
@@ -573,10 +573,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{
const size_type __len = _M_check_len(1u, "vector::_M_realloc_append");
if (__len <= 0)
- __builtin_unreachable ();
+ __builtin_unreachable();
pointer __old_start = this->_M_impl._M_start;
pointer __old_finish = this->_M_impl._M_finish;
- const size_type __elems = end() - begin();
+ const size_type __elems = size();
pointer __new_start(this->_M_allocate(__len));
pointer __new_finish(__new_start);
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 282667e..f4ba501 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -649,7 +649,7 @@ ftms = {
};
values = {
v = 1;
- /* For when there's no gthread. */
+ // For when there is no gthread.
cxxmin = 17;
hosted = yes;
gthread = no;
@@ -679,8 +679,6 @@ ftms = {
values = {
v = 201703;
cxxmin = 17;
- hosted = yes;
- gthread = yes;
};
};
@@ -854,6 +852,14 @@ ftms = {
};
ftms = {
+ name = optional_range_support;
+ values = {
+ v = 202406;
+ cxxmin = 26;
+ };
+};
+
+ftms = {
name = destroying_delete;
values = {
v = 201806;
@@ -1000,6 +1006,15 @@ ftms = {
};
ftms = {
+ name = mdspan;
+ no_stdname = true; // FIXME: remove
+ values = {
+ v = 1; // FIXME: 202207
+ cxxmin = 23;
+ };
+};
+
+ftms = {
name = ssize;
values = {
v = 201902;
@@ -1356,7 +1371,7 @@ ftms = {
v = 201907;
cxxmin = 20;
hosted = yes;
- extra_cond = "__glibcxx_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE";
+ extra_cond = "__glibcxx_atomic_wait";
};
};
@@ -1654,6 +1669,14 @@ ftms = {
};
ftms = {
+ name = ranges_starts_ends_with;
+ values = {
+ v = 202106;
+ cxxmin = 23;
+ };
+};
+
+ftms = {
name = constexpr_bitset;
values = {
v = 202202;
@@ -1741,6 +1764,23 @@ ftms = {
};
ftms = {
+ name = copyable_function;
+ values = {
+ v = 202306;
+ cxxmin = 26;
+ hosted = yes;
+ };
+};
+
+ftms = {
+ name = function_ref;
+ values = {
+ v = 202306;
+ cxxmin = 26;
+ };
+};
+
+ftms = {
name = out_ptr;
values = {
v = 202311;
@@ -1945,6 +1985,51 @@ ftms = {
};
};
+ftms = {
+ name = indirect;
+ values = {
+ v = 202502;
+ cxxmin = 26;
+ hosted = yes;
+ };
+};
+
+ftms = {
+ name = polymorphic;
+ values = {
+ v = 202502;
+ cxxmin = 26;
+ hosted = yes;
+ };
+};
+
+ftms = {
+ name = sstream_from_string_view;
+ values = {
+ v = 202306;
+ cxxmin = 26;
+ hosted = yes;
+ };
+};
+
+ftms = {
+ name = type_order;
+ values = {
+ v = 202506;
+ cxxmin = 26;
+ extra_cond = "__has_builtin(__builtin_type_order) "
+ "&& __cpp_lib_three_way_comparison >= 201907L";
+ };
+};
+
+ftms = {
+ name = exception_ptr_cast;
+ values = {
+ v = 202506;
+ cxxmin = 26;
+ };
+};
+
// Standard test specifications.
stds[97] = ">= 199711L";
stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index bb7c047..dc8ac07 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -751,7 +751,7 @@
#undef __glibcxx_want_parallel_algorithm
#if !defined(__cpp_lib_scoped_lock)
-# if (__cplusplus >= 201703L) && defined(_GLIBCXX_HAS_GTHREADS) && _GLIBCXX_HOSTED
+# if (__cplusplus >= 201703L)
# define __glibcxx_scoped_lock 201703L
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_scoped_lock)
# define __cpp_lib_scoped_lock 201703L
@@ -955,6 +955,16 @@
#endif /* !defined(__cpp_lib_optional) && defined(__glibcxx_want_optional) */
#undef __glibcxx_want_optional
+#if !defined(__cpp_lib_optional_range_support)
+# if (__cplusplus > 202302L)
+# define __glibcxx_optional_range_support 202406L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_optional_range_support)
+# define __cpp_lib_optional_range_support 202406L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_optional_range_support) && defined(__glibcxx_want_optional_range_support) */
+#undef __glibcxx_want_optional_range_support
+
#if !defined(__cpp_lib_destroying_delete)
# if (__cplusplus >= 202002L) && (__cpp_impl_destroying_delete)
# define __glibcxx_destroying_delete 201806L
@@ -1114,6 +1124,15 @@
#endif /* !defined(__cpp_lib_span) && defined(__glibcxx_want_span) */
#undef __glibcxx_want_span
+#if !defined(__cpp_lib_mdspan)
+# if (__cplusplus >= 202100L)
+# define __glibcxx_mdspan 1L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_mdspan)
+# endif
+# endif
+#endif /* !defined(__cpp_lib_mdspan) && defined(__glibcxx_want_mdspan) */
+#undef __glibcxx_want_mdspan
+
#if !defined(__cpp_lib_ssize)
# if (__cplusplus >= 202002L)
# define __glibcxx_ssize 201902L
@@ -1490,7 +1509,7 @@
#undef __glibcxx_want_move_iterator_concept
#if !defined(__cpp_lib_semaphore)
-# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED && (__glibcxx_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE)
+# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED && (__glibcxx_atomic_wait)
# define __glibcxx_semaphore 201907L
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_semaphore)
# define __cpp_lib_semaphore 201907L
@@ -1839,6 +1858,16 @@
#endif /* !defined(__cpp_lib_ranges_find_last) && defined(__glibcxx_want_ranges_find_last) */
#undef __glibcxx_want_ranges_find_last
+#if !defined(__cpp_lib_ranges_starts_ends_with)
+# if (__cplusplus >= 202100L)
+# define __glibcxx_ranges_starts_ends_with 202106L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_starts_ends_with)
+# define __cpp_lib_ranges_starts_ends_with 202106L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_ranges_starts_ends_with) && defined(__glibcxx_want_ranges_starts_ends_with) */
+#undef __glibcxx_want_ranges_starts_ends_with
+
#if !defined(__cpp_lib_constexpr_bitset)
# if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED && (__cpp_constexpr_dynamic_alloc)
# define __glibcxx_constexpr_bitset 202202L
@@ -1939,6 +1968,26 @@
#endif /* !defined(__cpp_lib_move_only_function) && defined(__glibcxx_want_move_only_function) */
#undef __glibcxx_want_move_only_function
+#if !defined(__cpp_lib_copyable_function)
+# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
+# define __glibcxx_copyable_function 202306L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_copyable_function)
+# define __cpp_lib_copyable_function 202306L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_copyable_function) && defined(__glibcxx_want_copyable_function) */
+#undef __glibcxx_want_copyable_function
+
+#if !defined(__cpp_lib_function_ref)
+# if (__cplusplus > 202302L)
+# define __glibcxx_function_ref 202306L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_function_ref)
+# define __cpp_lib_function_ref 202306L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_function_ref) && defined(__glibcxx_want_function_ref) */
+#undef __glibcxx_want_function_ref
+
#if !defined(__cpp_lib_out_ptr)
# if (__cplusplus >= 202100L)
# define __glibcxx_out_ptr 202311L
@@ -2174,4 +2223,54 @@
#endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) */
#undef __glibcxx_want_modules
+#if !defined(__cpp_lib_indirect)
+# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
+# define __glibcxx_indirect 202502L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_indirect)
+# define __cpp_lib_indirect 202502L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_indirect) && defined(__glibcxx_want_indirect) */
+#undef __glibcxx_want_indirect
+
+#if !defined(__cpp_lib_polymorphic)
+# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
+# define __glibcxx_polymorphic 202502L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_polymorphic)
+# define __cpp_lib_polymorphic 202502L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_polymorphic) && defined(__glibcxx_want_polymorphic) */
+#undef __glibcxx_want_polymorphic
+
+#if !defined(__cpp_lib_sstream_from_string_view)
+# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
+# define __glibcxx_sstream_from_string_view 202306L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_sstream_from_string_view)
+# define __cpp_lib_sstream_from_string_view 202306L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_sstream_from_string_view) && defined(__glibcxx_want_sstream_from_string_view) */
+#undef __glibcxx_want_sstream_from_string_view
+
+#if !defined(__cpp_lib_type_order)
+# if (__cplusplus > 202302L) && (__has_builtin(__builtin_type_order) && __cpp_lib_three_way_comparison >= 201907L)
+# define __glibcxx_type_order 202506L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_type_order)
+# define __cpp_lib_type_order 202506L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_type_order) && defined(__glibcxx_want_type_order) */
+#undef __glibcxx_want_type_order
+
+#if !defined(__cpp_lib_exception_ptr_cast)
+# if (__cplusplus > 202302L)
+# define __glibcxx_exception_ptr_cast 202506L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_exception_ptr_cast)
+# define __cpp_lib_exception_ptr_cast 202506L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_exception_ptr_cast) && defined(__glibcxx_want_exception_ptr_cast) */
+#undef __glibcxx_want_exception_ptr_cast
+
#undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/c_global/ccomplex b/libstdc++-v3/include/c_global/ccomplex
index 7044cf7..a39273f 100644
--- a/libstdc++-v3/include/c_global/ccomplex
+++ b/libstdc++-v3/include/c_global/ccomplex
@@ -24,6 +24,8 @@
/** @file include/ccomplex
* This is a Standard C++ Library header.
+ *
+ * @since C++11 (removed in C++20)
*/
#ifndef _GLIBCXX_CCOMPLEX
diff --git a/libstdc++-v3/include/c_global/ciso646 b/libstdc++-v3/include/c_global/ciso646
index a663e04..6dec7df 100644
--- a/libstdc++-v3/include/c_global/ciso646
+++ b/libstdc++-v3/include/c_global/ciso646
@@ -28,6 +28,8 @@
*
* This is the C++ version of the Standard C Library header @c iso646.h,
* which is empty in C++.
+ *
+ * @since C++11 (removed in C++20)
*/
#ifndef _GLIBCXX_CISO646
#define _GLIBCXX_CISO646
@@ -38,13 +40,15 @@
#include <bits/c++config.h>
-#if __cplusplus >= 202002L && ! _GLIBCXX_USE_DEPRECATED
-# error "<ciso646> is not a standard header in C++20, use <version> to detect implementation-specific macros"
-#elif __cplusplus >= 201703L && defined __DEPRECATED
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wc++23-extensions"
-# warning "<ciso646> is deprecated in C++17, use <version> to detect implementation-specific macros"
-# pragma GCC diagnostic pop
+#if __cplusplus >= 202002L
+# if ! _GLIBCXX_USE_DEPRECATED
+# error "<ciso646> is not a standard header since C++20, use <version> to detect implementation-specific macros"
+# elif defined __DEPRECATED
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wc++23-extensions"
+# warning "<ciso646> is not a standard header since C++20, use <version> to detect implementation-specific macros"
+# pragma GCC diagnostic pop
+# endif
#endif
#endif
diff --git a/libstdc++-v3/include/c_global/cstdalign b/libstdc++-v3/include/c_global/cstdalign
index 92e0ad6..41ce506 100644
--- a/libstdc++-v3/include/c_global/cstdalign
+++ b/libstdc++-v3/include/c_global/cstdalign
@@ -24,6 +24,8 @@
/** @file include/cstdalign
* This is a Standard C++ Library header.
+ *
+ * @since C++11 (removed in C++20)
*/
#ifndef _GLIBCXX_CSTDALIGN
diff --git a/libstdc++-v3/include/c_global/cstdbool b/libstdc++-v3/include/c_global/cstdbool
index e75f56c..5933d7d 100644
--- a/libstdc++-v3/include/c_global/cstdbool
+++ b/libstdc++-v3/include/c_global/cstdbool
@@ -24,6 +24,8 @@
/** @file include/cstdbool
* This is a Standard C++ Library header.
+ *
+ * @since C++11 (removed in C++20)
*/
#ifndef _GLIBCXX_CSTDBOOL
diff --git a/libstdc++-v3/include/c_global/ctgmath b/libstdc++-v3/include/c_global/ctgmath
index 0a5a0e7..b708878 100644
--- a/libstdc++-v3/include/c_global/ctgmath
+++ b/libstdc++-v3/include/c_global/ctgmath
@@ -24,6 +24,8 @@
/** @file include/ctgmath
* This is a Standard C++ Library header.
+ *
+ * @since C++11 (removed in C++20)
*/
#ifndef _GLIBCXX_CTGMATH
diff --git a/libstdc++-v3/include/debug/debug.h b/libstdc++-v3/include/debug/debug.h
index 0e02d58..0131c0a 100644
--- a/libstdc++-v3/include/debug/debug.h
+++ b/libstdc++-v3/include/debug/debug.h
@@ -58,7 +58,7 @@ namespace __gnu_debug
using namespace std::__debug;
template<typename _Ite, typename _Seq, typename _Cat>
- struct _Safe_iterator;
+ class _Safe_iterator;
}
#if ! defined _GLIBCXX_DEBUG || ! _GLIBCXX_HOSTED
diff --git a/libstdc++-v3/include/ext/atomicity.h b/libstdc++-v3/include/ext/atomicity.h
index 98f745c..650b786 100644
--- a/libstdc++-v3/include/ext/atomicity.h
+++ b/libstdc++-v3/include/ext/atomicity.h
@@ -61,7 +61,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// To abstract locking primitives across all thread policies, use:
// __exchange_and_add_dispatch
// __atomic_add_dispatch
-#ifdef _GLIBCXX_ATOMIC_BUILTINS
+#ifdef _GLIBCXX_ATOMIC_WORD_BUILTINS
inline _Atomic_word
__attribute__((__always_inline__))
__exchange_and_add(volatile _Atomic_word* __mem, int __val)
@@ -71,7 +71,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__attribute__((__always_inline__))
__atomic_add(volatile _Atomic_word* __mem, int __val)
{ __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }
-#else
+#else // Defined in config/cpu/.../atomicity.h
_Atomic_word
__exchange_and_add(volatile _Atomic_word*, int) _GLIBCXX_NOTHROW;
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp
index 6088709..a8c73b5 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp
@@ -305,6 +305,9 @@ namespace __gnu_pbds
rotate_parent(node_pointer);
inline void
+ update_subtree_size(node_pointer);
+
+ inline void
apply_update(node_pointer, null_node_update_pointer);
template<typename Node_Update_>
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp
index e6e954d..b8f5014 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp
@@ -122,7 +122,6 @@ insert_leaf_new(const_reference r_value, node_pointer p_nd, bool left_nd)
}
p_new_nd->m_p_parent = p_nd;
- p_new_nd->m_p_left = p_new_nd->m_p_right = 0;
PB_DS_ASSERT_NODE_CONSISTENT(p_nd)
update_to_top(p_new_nd, (node_update* )this);
@@ -142,7 +141,6 @@ insert_imp_empty(const_reference r_value)
m_p_head->m_p_parent = p_new_node;
p_new_node->m_p_parent = m_p_head;
- p_new_node->m_p_left = p_new_node->m_p_right = 0;
_GLIBCXX_DEBUG_ONLY(debug_base::insert_new(PB_DS_V2F(r_value));)
update_to_top(m_p_head->m_p_parent, (node_update*)this);
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp
index 069b17f..8cadce2 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp
@@ -122,8 +122,23 @@ rotate_parent(node_pointer p_nd)
PB_DS_CLASS_T_DEC
inline void
PB_DS_CLASS_C_DEC::
-apply_update(node_pointer /*p_nd*/, null_node_update_pointer /*p_update*/)
-{ }
+update_subtree_size(node_pointer p_nd)
+{
+ size_type size = 1;
+ if (p_nd->m_p_left)
+ size += p_nd->m_p_left->m_subtree_size;
+ if (p_nd->m_p_right)
+ size += p_nd->m_p_right->m_subtree_size;
+ p_nd->m_subtree_size = size;
+}
+
+PB_DS_CLASS_T_DEC
+inline void
+PB_DS_CLASS_C_DEC::
+apply_update(node_pointer p_nd, null_node_update_pointer /*p_update*/)
+{
+ update_subtree_size(p_nd);
+}
PB_DS_CLASS_T_DEC
template<typename Node_Update_>
@@ -131,6 +146,7 @@ inline void
PB_DS_CLASS_C_DEC::
apply_update(node_pointer p_nd, Node_Update_* /*p_update*/)
{
+ update_subtree_size(p_nd);
node_update::operator()(node_iterator(p_nd),
node_const_iterator(static_cast<node_pointer>(0)));
}
@@ -152,7 +168,14 @@ update_to_top(node_pointer p_nd, Node_Update_* p_update)
PB_DS_CLASS_T_DEC
inline void
PB_DS_CLASS_C_DEC::
-update_to_top(node_pointer /*p_nd*/, null_node_update_pointer /*p_update*/)
-{ }
+update_to_top(node_pointer p_nd, null_node_update_pointer /*p_update */)
+{
+ while (p_nd != m_p_head)
+ {
+ update_subtree_size(p_nd);
+
+ p_nd = p_nd->m_p_parent;
+ }
+}
#endif
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp
index 0c1b26f..a2a5775 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp
@@ -133,7 +133,9 @@ PB_DS_CLASS_C_DEC::
split_finish(PB_DS_CLASS_C_DEC& other)
{
other.initialize_min_max();
- other.m_size = std::distance(other.begin(), other.end());
+ other.m_size = 0;
+ if (other.m_p_head->m_p_parent != 0)
+ other.m_size = other.m_p_head->m_p_parent->m_subtree_size;
m_size -= other.m_size;
initialize_min_max();
PB_DS_ASSERT_VALID((*this))
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/node.hpp b/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/node.hpp
index f229be7..3803ddb 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/node.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/node.hpp
@@ -58,6 +58,9 @@ namespace __gnu_pbds
typedef typename rebind_traits<_Alloc, rb_tree_node_>::pointer
node_pointer;
+ typedef typename rebind_traits<_Alloc, rb_tree_node_>::size_type
+ size_type;
+
typedef typename rebind_traits<_Alloc, metadata_type>::reference
metadata_reference;
@@ -88,6 +91,7 @@ namespace __gnu_pbds
node_pointer m_p_left;
node_pointer m_p_right;
node_pointer m_p_parent;
+ size_type m_subtree_size;
value_type m_value;
bool m_red;
metadata_type m_metadata;
@@ -100,6 +104,9 @@ namespace __gnu_pbds
typedef Value_Type value_type;
typedef null_type metadata_type;
+ typedef typename rebind_traits<_Alloc, rb_tree_node_>::size_type
+ size_type;
+
typedef typename rebind_traits<_Alloc, rb_tree_node_>::pointer
node_pointer;
@@ -116,6 +123,7 @@ namespace __gnu_pbds
node_pointer m_p_left;
node_pointer m_p_right;
node_pointer m_p_parent;
+ size_type m_subtree_size;
value_type m_value;
bool m_red;
};
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/node.hpp b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/node.hpp
index 961afbe..b5fbb50 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/node.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/node.hpp
@@ -56,6 +56,9 @@ namespace __gnu_pbds
typedef typename rebind_traits<_Alloc, splay_tree_node_>::pointer
node_pointer;
+ typedef typename rebind_traits<_Alloc, splay_tree_node_>::size_type
+ size_type;
+
typedef typename rebind_traits<_Alloc, metadata_type>::reference
metadata_reference;
@@ -85,6 +88,7 @@ namespace __gnu_pbds
node_pointer m_p_left;
node_pointer m_p_right;
node_pointer m_p_parent;
+ size_type m_subtree_size;
metadata_type m_metadata;
};
@@ -98,6 +102,9 @@ namespace __gnu_pbds
typedef typename rebind_traits<_Alloc, splay_tree_node_>::pointer
node_pointer;
+ typedef typename rebind_traits<_Alloc, splay_tree_node_>::size_type
+ size_type;
+
inline bool
special() const
{ return m_special; }
@@ -111,6 +118,7 @@ namespace __gnu_pbds
node_pointer m_p_left;
node_pointer m_p_right;
node_pointer m_p_parent;
+ size_type m_subtree_size;
value_type m_value;
bool m_special;
};
diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h
index f4b312d..e7d89c9 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -228,6 +228,7 @@
#include <flat_map>
#include <flat_set>
#include <generator>
+#include <mdspan>
#include <print>
#include <spanstream>
#include <stacktrace>
diff --git a/libstdc++-v3/include/pstl/glue_numeric_impl.h b/libstdc++-v3/include/pstl/glue_numeric_impl.h
index 10d4912..fe2d0fd 100644
--- a/libstdc++-v3/include/pstl/glue_numeric_impl.h
+++ b/libstdc++-v3/include/pstl/glue_numeric_impl.h
@@ -25,7 +25,7 @@ __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _Tp>
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init,
_BinaryOperation __binary_op)
{
- return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, __init, __binary_op,
+ return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, std::move(__init), __binary_op,
__pstl::__internal::__no_op());
}
@@ -33,7 +33,7 @@ template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _Tp>
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init)
{
- return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, __init, std::plus<_Tp>(),
+ return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, std::move(__init), std::plus<_Tp>(),
__pstl::__internal::__no_op());
}
@@ -58,7 +58,7 @@ transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _Forward
typedef typename iterator_traits<_ForwardIterator1>::value_type _InputType;
return __pstl::__internal::__pattern_transform_reduce(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec),
- __first1, __last1, __first2, __init, std::plus<_InputType>(),
+ __first1, __last1, __first2, std::move(__init), std::plus<_InputType>(),
std::multiplies<_InputType>());
}
@@ -70,7 +70,7 @@ transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _Forward
{
auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first1, __first2);
return __pstl::__internal::__pattern_transform_reduce(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec),
- __first1, __last1, __first2, __init, __binary_op1,
+ __first1, __last1, __first2, std::move(__init), __binary_op1,
__binary_op2);
}
@@ -81,7 +81,7 @@ transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIt
{
auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first);
return __pstl::__internal::__pattern_transform_reduce(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec),
- __first, __last, __init, __binary_op, __unary_op);
+ __first, __last, std::move(__init), __binary_op, __unary_op);
}
// [exclusive.scan]
@@ -139,7 +139,7 @@ inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIte
_ForwardIterator2 __result, _BinaryOperation __binary_op, _Tp __init)
{
return transform_inclusive_scan(std::forward<_ExecutionPolicy>(__exec), __first, __last, __result, __binary_op,
- __pstl::__internal::__no_op(), __init);
+ __pstl::__internal::__no_op(), std::move(__init));
}
// [transform.exclusive.scan]
@@ -154,7 +154,7 @@ transform_exclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _
auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first, __result);
return __pstl::__internal::__pattern_transform_scan(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec), __first,
- __last, __result, __unary_op, __init, __binary_op,
+ __last, __result, __unary_op, std::move(__init), __binary_op,
/*inclusive=*/std::false_type());
}
@@ -170,7 +170,7 @@ transform_inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _
auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first, __result);
return __pstl::__internal::__pattern_transform_scan(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec), __first,
- __last, __result, __unary_op, __init, __binary_op,
+ __last, __result, __unary_op, std::move(__init), __binary_op,
/*inclusive=*/std::true_type());
}
diff --git a/libstdc++-v3/include/pstl/numeric_impl.h b/libstdc++-v3/include/pstl/numeric_impl.h
index e1ebec1..b285a66 100644
--- a/libstdc++-v3/include/pstl/numeric_impl.h
+++ b/libstdc++-v3/include/pstl/numeric_impl.h
@@ -35,7 +35,7 @@ __brick_transform_reduce(_ForwardIterator1 __first1, _ForwardIterator1 __last1,
_BinaryOperation1 __binary_op1, _BinaryOperation2 __binary_op2,
/*is_vector=*/std::false_type) noexcept
{
- return std::inner_product(__first1, __last1, __first2, __init, __binary_op1, __binary_op2);
+ return std::inner_product(__first1, __last1, __first2, std::move(__init), __binary_op1, __binary_op2);
}
template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _Tp, class _BinaryOperation1,
@@ -48,7 +48,7 @@ __brick_transform_reduce(_RandomAccessIterator1 __first1, _RandomAccessIterator1
{
typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type _DifferenceType;
return __unseq_backend::__simd_transform_reduce(
- __last1 - __first1, __init, __binary_op1,
+ __last1 - __first1, std::move(__init), __binary_op1,
[=, &__binary_op2](_DifferenceType __i) { return __binary_op2(__first1[__i], __first2[__i]); });
}
@@ -59,7 +59,7 @@ __pattern_transform_reduce(_Tag, _ExecutionPolicy&&, _ForwardIterator1 __first1,
_ForwardIterator2 __first2, _Tp __init, _BinaryOperation1 __binary_op1,
_BinaryOperation2 __binary_op2) noexcept
{
- return __brick_transform_reduce(__first1, __last1, __first2, __init, __binary_op1, __binary_op2,
+ return __brick_transform_reduce(__first1, __last1, __first2, std::move(__init), __binary_op1, __binary_op2,
typename _Tag::__is_vector{});
}
@@ -79,12 +79,12 @@ __pattern_transform_reduce(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& _
__backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __first1, __last1,
[__first1, __first2, __binary_op2](_RandomAccessIterator1 __i) mutable
{ return __binary_op2(*__i, *(__first2 + (__i - __first1))); },
- __init,
+ std::move(__init),
__binary_op1, // Combine
[__first1, __first2, __binary_op1, __binary_op2](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j,
_Tp __init) -> _Tp
{
- return __internal::__brick_transform_reduce(__i, __j, __first2 + (__i - __first1), __init,
+ return __internal::__brick_transform_reduce(__i, __j, __first2 + (__i - __first1), std::move(__init),
__binary_op1, __binary_op2, _IsVector{});
});
});
@@ -99,7 +99,7 @@ _Tp
__brick_transform_reduce(_ForwardIterator __first, _ForwardIterator __last, _Tp __init, _BinaryOperation __binary_op,
_UnaryOperation __unary_op, /*is_vector=*/std::false_type) noexcept
{
- return std::transform_reduce(__first, __last, __init, __binary_op, __unary_op);
+ return std::transform_reduce(__first, __last, std::move(__init), __binary_op, __unary_op);
}
template <class _RandomAccessIterator, class _Tp, class _UnaryOperation, class _BinaryOperation>
@@ -110,7 +110,7 @@ __brick_transform_reduce(_RandomAccessIterator __first, _RandomAccessIterator __
{
typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _DifferenceType;
return __unseq_backend::__simd_transform_reduce(
- __last - __first, __init, __binary_op,
+ __last - __first, std::move(__init), __binary_op,
[=, &__unary_op](_DifferenceType __i) { return __unary_op(__first[__i]); });
}
@@ -120,7 +120,7 @@ _Tp
__pattern_transform_reduce(_Tag, _ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Tp __init,
_BinaryOperation __binary_op, _UnaryOperation __unary_op) noexcept
{
- return __internal::__brick_transform_reduce(__first, __last, __init, __binary_op, __unary_op,
+ return __internal::__brick_transform_reduce(__first, __last, std::move(__init), __binary_op, __unary_op,
typename _Tag::__is_vector{});
}
@@ -138,9 +138,9 @@ __pattern_transform_reduce(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& _
{
return __par_backend::__parallel_transform_reduce(
__backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __first, __last,
- [__unary_op](_RandomAccessIterator __i) mutable { return __unary_op(*__i); }, __init, __binary_op,
+ [__unary_op](_RandomAccessIterator __i) mutable { return __unary_op(*__i); }, std::move(__init), __binary_op,
[__unary_op, __binary_op](_RandomAccessIterator __i, _RandomAccessIterator __j, _Tp __init) {
- return __internal::__brick_transform_reduce(__i, __j, __init, __binary_op, __unary_op, _IsVector{});
+ return __internal::__brick_transform_reduce(__i, __j, std::move(__init), __binary_op, __unary_op, _IsVector{});
});
});
}
@@ -181,7 +181,7 @@ __brick_transform_scan(_RandomAccessIterator __first, _RandomAccessIterator __la
__init = __binary_op(__init, __unary_op(*__first));
*__result = __init;
}
- return std::make_pair(__result, __init);
+ return std::make_pair(__result, std::move(__init));
}
// type is arithmetic and binary operation is a user defined operation.
@@ -199,11 +199,11 @@ __brick_transform_scan(_RandomAccessIterator __first, _RandomAccessIterator __la
/*is_vector=*/std::true_type) noexcept
{
#if defined(_PSTL_UDS_PRESENT)
- return __unseq_backend::__simd_scan(__first, __last - __first, __result, __unary_op, __init, __binary_op,
+ return __unseq_backend::__simd_scan(__first, __last - __first, __result, __unary_op, std::move(__init), __binary_op,
_Inclusive());
#else
// We need to call serial brick here to call function for inclusive and exclusive scan that depends on _Inclusive() value
- return __internal::__brick_transform_scan(__first, __last, __result, __unary_op, __init, __binary_op, _Inclusive(),
+ return __internal::__brick_transform_scan(__first, __last, __result, __unary_op, std::move(__init), __binary_op, _Inclusive(),
/*is_vector=*/std::false_type());
#endif
}
@@ -215,7 +215,7 @@ __brick_transform_scan(_RandomAccessIterator __first, _RandomAccessIterator __la
_UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op, _Inclusive,
/*is_vector=*/std::true_type) noexcept
{
- return __internal::__brick_transform_scan(__first, __last, __result, __unary_op, __init, __binary_op, _Inclusive(),
+ return __internal::__brick_transform_scan(__first, __last, __result, __unary_op, std::move(__init), __binary_op, _Inclusive(),
/*is_vector=*/std::false_type());
}
@@ -247,19 +247,19 @@ __pattern_transform_scan(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& __e
{
__par_backend::__parallel_transform_scan(
__backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __last - __first,
- [__first, __unary_op](_DifferenceType __i) mutable { return __unary_op(__first[__i]); }, __init,
+ [__first, __unary_op](_DifferenceType __i) mutable { return __unary_op(__first[__i]); }, std::move(__init),
__binary_op,
[__first, __unary_op, __binary_op](_DifferenceType __i, _DifferenceType __j, _Tp __init)
{
// Execute serial __brick_transform_reduce, due to the explicit SIMD vectorization (reduction) requires a commutative operation for the guarantee of correct scan.
- return __internal::__brick_transform_reduce(__first + __i, __first + __j, __init, __binary_op,
+ return __internal::__brick_transform_reduce(__first + __i, __first + __j, std::move(__init), __binary_op,
__unary_op,
/*__is_vector*/ std::false_type());
},
[__first, __unary_op, __binary_op, __result](_DifferenceType __i, _DifferenceType __j, _Tp __init)
{
return __internal::__brick_transform_scan(__first + __i, __first + __j, __result + __i, __unary_op,
- __init, __binary_op, _Inclusive(), _IsVector{})
+ std::move(__init), __binary_op, _Inclusive(), _IsVector{})
.second;
});
return __result + (__last - __first);
@@ -286,7 +286,7 @@ __pattern_transform_scan(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& __e
[&]()
{
__par_backend::__parallel_strict_scan(
- __backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __n, __init,
+ __backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __n, std::move(__init),
[__first, __unary_op, __binary_op, __result](_DifferenceType __i, _DifferenceType __len)
{
return __internal::__brick_transform_scan(__first + __i, __first + (__i + __len), __result + __i,
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/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 5187c96..fd75edf 100644
--- a/libstdc++-v3/include/std/bit
+++ b/libstdc++-v3/include/std/bit
@@ -166,7 +166,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// 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;
@@ -188,7 +188,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// 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;
diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono
index 8eb9fd9..cb8213e 100644
--- a/libstdc++-v3/include/std/chrono
+++ b/libstdc++-v3/include/std/chrono
@@ -2305,8 +2305,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__r *= 10;
return __r;
}
-
- template<typename _Duration> struct __utc_leap_second;
}
/// @endcond
@@ -2481,30 +2479,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
diff --git a/libstdc++-v3/include/std/complex b/libstdc++-v3/include/std/complex
index 59ef905..d9d2d8a 100644
--- a/libstdc++-v3/include/std/complex
+++ b/libstdc++-v3/include/std/complex
@@ -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)
@@ -2123,8 +2123,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 +2307,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 +2343,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 +2387,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 +2423,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 +2462,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 +2506,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 +2516,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/expected b/libstdc++-v3/include/std/expected
index 5dc1dfb..60f1565 100644
--- a/libstdc++-v3/include/std/expected
+++ b/libstdc++-v3/include/std/expected
@@ -1169,13 +1169,13 @@ namespace __expected
return !__y.has_value() && bool(__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>;
}
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); }
diff --git a/libstdc++-v3/include/std/flat_map b/libstdc++-v3/include/std/flat_map
index 6593988..de006ad 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]]
@@ -895,7 +898,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
auto __guard = _M_make_clear_guard();
auto __zv = views::zip(_M_cont.keys, _M_cont.values);
- auto __sr = ranges::remove_if(__zv, __pred);
+ auto __sr = ranges::remove_if(__zv, __pred,
+ [](const auto& __e) {
+ return const_reference(__e);
+ });
auto __erased = __sr.size();
erase(end() - __erased, end());
__guard._M_disable();
@@ -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; }
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 054ce35..46bd5d5 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -472,30 +472,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
+ _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
@@ -507,9 +510,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;
@@ -517,12 +528,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;
@@ -562,7 +572,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;
@@ -571,14 +581,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;
@@ -603,7 +613,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;
@@ -871,7 +881,7 @@ 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,
@@ -896,12 +906,12 @@ namespace __format
}
}
-
- // Values are indices into _Escapes::all.
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
@@ -912,10 +922,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); }
@@ -947,6 +953,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>
@@ -991,9 +1012,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;
};
@@ -1062,9 +1083,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());
}
}
@@ -1177,8 +1197,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);
@@ -1189,8 +1208,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>.
@@ -1312,11 +1330,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
@@ -1332,7 +1353,7 @@ namespace __format
format(basic_string_view<_CharT> __s,
basic_format_context<_Out, _CharT>& __fc) const
{
- if (_M_spec._M_type == _Pres_esc)
+ if (_M_spec._M_debug)
return _M_format_escaped(__s, __fc);
if (_M_spec._M_width_kind == _WP_none
@@ -1349,22 +1370,21 @@ namespace __format
_M_format_escaped(basic_string_view<_CharT> __s,
basic_format_context<_Out, _CharT>& __fc) const
{
- constexpr auto __term = __format::_Term_char::_Tc_quote;
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);
+ return __format::__write_escaped(__fc.out(), __s, _Term_quote);
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);
+ return __format::__write_escaped(__fc.out(), __s, _Term_quote);
// 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.
_Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth, __maxwidth);
- __format::__write_escaped(__sink.out(), __s, __term);
+ __format::__write_escaped(__sink.out(), __s, _Term_quote);
return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill);
}
@@ -1388,7 +1408,7 @@ namespace __format
size_t(ranges::distance(__rg)));
return format(__str, __fc);
}
- else if (_M_spec._M_type != _Pres_esc)
+ else if (!_M_spec._M_debug)
{
const size_t __padwidth = _M_spec._M_get_width(__fc);
if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none)
@@ -1441,7 +1461,7 @@ namespace __format
constexpr void
set_debug_format() noexcept
- { _M_spec._M_type = _Pres_esc; }
+ { _M_spec._M_debug = true; }
#endif
private:
@@ -1462,7 +1482,10 @@ namespace __format
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)
@@ -1551,7 +1574,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;
@@ -1559,7 +1582,7 @@ namespace __format
case '?':
if (__type == _AsChar)
{
- __spec._M_type = _Pres_esc;
+ __spec._M_debug = true;
++__first;
}
#endif
@@ -1580,7 +1603,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'");
@@ -1589,8 +1613,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 "
@@ -1702,51 +1727,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);
- 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);
+ if (!_M_spec._M_debug)
+ return __format::__write_padded_as_spec(__in, __width,
+ __fc, _M_spec);
+
+ __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);
}
@@ -1863,20 +1871,24 @@ namespace __format
_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__
@@ -1910,14 +1922,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.
@@ -2386,9 +2398,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)
@@ -2419,17 +2438,18 @@ namespace __format
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)
+ 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] {
+ auto __finalize = [this, &__spec, __type] {
_M_spec = __spec;
+ _M_set_default(__type);
};
auto __finished = [&] {
@@ -2457,19 +2477,23 @@ namespace __format
#endif
__first = __spec._M_parse_width(__first, __last, __pc);
+ if (__finished())
+ return __first;
- if (__first != __last)
+ if (*__first == 'p')
{
- if (*__first == 'p')
- ++__first;
+ __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 = __format::_Pres_P;
- ++__first;
- }
-#endif
+ else if (*__first == 'P')
+ {
+ __spec._M_type = _Pres_P;
+ _M_spec._M_alt = !_M_spec._M_alt;
+ ++__first;
}
+#endif
if (__finished())
return __first;
@@ -2536,6 +2560,17 @@ namespace __format
}
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{};
};
@@ -2558,11 +2593,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);
}
@@ -2570,7 +2602,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:
@@ -2594,11 +2626,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);
}
@@ -2606,7 +2635,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:
@@ -2947,8 +2976,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>
{
@@ -2962,17 +2991,45 @@ 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 > 1
+ // Reuse __formatter_fp<C>::format<__format::__flt128_t, Out> for __float128.
+ // This formatter is not declared if _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT is true,
+ // as __float128 when present is same type as __ieee128, which may be same as
+ // long double.
+ 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;
+
+ static_assert( !is_same_v<__float128, long double>,
+ "This specialization should not be used for long double" );
+ };
+#endif
+
#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;
@@ -3057,24 +3114,28 @@ namespace __format
// _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
/// An iterator after the last character written, and the number of
@@ -3144,6 +3205,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 +3328,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;
@@ -3488,6 +3558,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
@@ -3550,6 +3628,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
{
@@ -3636,17 +3722,15 @@ namespace __format
template<typename _Out, typename _CharT>
class _Padding_sink : public _Str_sink<_CharT>
{
- const size_t _M_padwidth;
- const size_t _M_maxwidth;
+ 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;
- }
+ { return _M_printwidth >= _M_maxwidth; }
[[__gnu__::__always_inline__]]
bool
@@ -3660,11 +3744,20 @@ namespace __format
}
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();
}
@@ -3682,7 +3775,10 @@ namespace __format
// 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_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
@@ -3718,6 +3814,10 @@ namespace __format
_Str_sink<_CharT>::_M_overflow();
}
+ bool
+ _M_discarding() const override
+ { return _M_ignoring(); }
+
typename _Sink<_CharT>::_Reservation
_M_reserve(size_t __n) override
{
@@ -3752,15 +3852,16 @@ namespace __format
public:
[[__gnu__::__always_inline__]]
- explicit _Padding_sink(_Out __out, size_t __padwidth)
- : _M_padwidth(__padwidth), _M_maxwidth(-1),
+ 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, size_t __maxwidth)
- : _M_padwidth(__padwidth), _M_maxwidth(__maxwidth),
- _M_out(std::move(__out)), _M_printwidth(0)
+ explicit
+ _Padding_sink(_Out __out, size_t __padwidth)
+ : _Padding_sink(std::move(__out), __padwidth, (size_t)-1)
{ }
_Out
@@ -3792,20 +3893,19 @@ namespace __format
}
};
- enum _Arg_t : unsigned char {
+ 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
@@ -3831,6 +3931,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;
@@ -3840,11 +3946,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
};
@@ -3882,10 +3994,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;
@@ -3899,9 +4015,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);
@@ -4080,36 +4208,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>)
@@ -4165,7 +4282,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;
@@ -4179,11 +4316,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;
}
@@ -4256,13 +4388,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:
@@ -4280,14 +4432,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();
}
}
@@ -4373,7 +4518,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
@@ -4386,7 +4531,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...>;
@@ -5338,24 +5483,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()
@@ -5725,7 +5853,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'");
@@ -5736,8 +5864,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"
@@ -5819,8 +5946,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);
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index 1077e96..307bcb9 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -52,6 +52,21 @@
#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_transparent_operators
+#include <bits/version.h>
+
#include <tuple>
#include <type_traits>
#include <bits/functional_hash.h>
@@ -72,23 +87,10 @@
# 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)
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
index dc147c2..9504df0 100644
--- a/libstdc++-v3/include/std/latch
+++ b/libstdc++-v3/include/std/latch
@@ -89,15 +89,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_ALWAYS_INLINE void
wait() const noexcept
{
- auto const __pred = [this] { return this->try_wait(); };
- std::__atomic_wait_address(&_M_counter, __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:
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
new file mode 100644
index 0000000..c72a640
--- /dev/null
+++ b/libstdc++-v3/include/std/mdspan
@@ -0,0 +1,1041 @@
+// <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 <limits>
+#include <utility>
+
+#define __glibcxx_want_mdspan
+#include <bits/version.h>
+
+#ifdef __glibcxx_mdspan
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ namespace __mdspan
+ {
+ template<typename _IndexType, array _Extents>
+ class _ExtentsStorage
+ {
+ public:
+ static consteval bool
+ _S_is_dyn(size_t __ext) noexcept
+ { return __ext == dynamic_extent; }
+
+ template<typename _OIndexType>
+ static constexpr _IndexType
+ _S_int_cast(const _OIndexType& __other) noexcept
+ { return _IndexType(__other); }
+
+ 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 auto _S_dynamic_index = [] 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 += _S_is_dyn(_Extents[__i]);
+ }
+ __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 auto _S_dynamic_index_inv = [] consteval
+ {
+ array<size_t, _S_rank_dynamic> __ret;
+ for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i)
+ if (_S_is_dyn(_Extents[__i]))
+ __ret[__r++] = __i;
+ return __ret;
+ }();
+
+ static constexpr size_t
+ _S_static_extent(size_t __r) noexcept
+ { return _Extents[__r]; }
+
+ constexpr _IndexType
+ _M_extent(size_t __r) const noexcept
+ {
+ auto __se = _Extents[__r];
+ if (__se == dynamic_extent)
+ return _M_dyn_exts[_S_dynamic_index[__r]];
+ else
+ return __se;
+ }
+
+ template<size_t _OtherRank, typename _GetOtherExtent>
+ constexpr void
+ _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept
+ {
+ 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 span<const size_t>
+ _S_static_extents(size_t __begin, size_t __end) noexcept
+ {
+ return {_Extents.data() + __begin, _Extents.data() + __end};
+ }
+
+ 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],
+ _M_dyn_exts + _S_dynamic_index[__end]};
+ }
+
+ private:
+ using _S_storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type;
+ [[no_unique_address]] _S_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 <= numeric_limits<_IndexType>::max();
+ }
+
+ namespace __mdspan
+ {
+ template<typename _Extents>
+ constexpr span<const size_t>
+ __static_extents(size_t __begin = 0, size_t __end = _Extents::rank())
+ noexcept
+ { return _Extents::_S_storage::_S_static_extents(__begin, __end); }
+
+ 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);
+ }
+ }
+
+ template<typename _IndexType, size_t... _Extents>
+ class extents
+ {
+ static_assert(__is_standard_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");
+
+ 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 _S_storage::_S_rank; }
+
+ static constexpr rank_type
+ rank_dynamic() noexcept { return _S_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 _S_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) || ...)
+ || (numeric_limits<index_type>::max()
+ < numeric_limits<_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{_S_storage::_S_int_cast(__exts)...}))
+ { }
+
+ template<__mdspan::__valid_index_type<index_type> _OIndexType, size_t _Nm>
+ requires (_Nm == rank() || _Nm == rank_dynamic())
+ constexpr explicit(_Nm != rank_dynamic())
+ extents(span<_OIndexType, _Nm> __exts) noexcept
+ : _M_exts(span<const _OIndexType, _Nm>(__exts))
+ { }
+
+ template<__mdspan::__valid_index_type<index_type> _OIndexType, size_t _Nm>
+ requires (_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
+ {
+ for (size_t __i = 0; __i < __self.rank(); ++__i)
+ if (!cmp_equal(__self.extent(__i), __other.extent(__i)))
+ return false;
+ return true;
+ }
+ }
+
+ private:
+ friend span<const size_t>
+ __mdspan::__static_extents<extents>(size_t, size_t);
+
+ friend span<const index_type>
+ __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t);
+
+ using _S_storage = __mdspan::_ExtentsStorage<
+ _IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>;
+ [[no_unique_address]] _S_storage _M_exts;
+
+ 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 _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;
+ }
+
+ constexpr size_t
+ __static_extents_prod(const auto& __sta_exts) noexcept
+ {
+ size_t __ret = 1;
+ for (auto __factor : __sta_exts)
+ if (__factor != dynamic_extent)
+ __ret *= __factor;
+ return __ret;
+ }
+
+ template<typename _Extents>
+ constexpr typename _Extents::index_type
+ __exts_prod(const _Extents& __exts, size_t __begin, size_t __end) noexcept
+ {
+ using _IndexType = typename _Extents::index_type;
+
+ size_t __ret = 1;
+ if constexpr (_Extents::rank_dynamic() != _Extents::rank())
+ {
+ auto __sta_exts = __static_extents<_Extents>(__begin, __end);
+ __ret = __static_extents_prod(__sta_exts);
+ if (__ret == 0)
+ return 0;
+ }
+
+ if constexpr (_Extents::rank_dynamic() > 0)
+ for (auto __factor : __dynamic_extents(__exts, __begin, __end))
+ __ret *= size_t(__factor);
+ return _IndexType(__ret);
+ }
+
+ template<typename _Extents>
+ constexpr typename _Extents::index_type
+ __fwd_prod(const _Extents& __exts, size_t __r) noexcept
+ { return __exts_prod(__exts, 0, __r); }
+
+ template<typename _Extents>
+ constexpr typename _Extents::index_type
+ __rev_prod(const _Extents& __exts, size_t __r) noexcept
+ { return __exts_prod(__exts, __r + 1, __exts.rank()); }
+
+ template<typename _IndexType, size_t... _Counts>
+ auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
+ -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
+
+ template<typename _Tp>
+ consteval size_t
+ __dynamic_extent() { return dynamic_extent; }
+ }
+
+ template<typename _IndexType, size_t _Rank>
+ using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>(
+ make_index_sequence<_Rank>()));
+
+ template<typename... _Integrals>
+ requires (is_convertible_v<_Integrals, size_t> && ...)
+ explicit extents(_Integrals...) ->
+ extents<size_t, __mdspan::__dynamic_extent<_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;
+ };
+
+ 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
+ {
+ __res += __idx * __mult;
+ __mult *= __exts.extent(__pos);
+ ++__pos;
+ };
+ (__update(__indices), ...);
+ }
+ return __res;
+ }
+
+ template<typename _Extents,
+ typename _IndexType = typename _Extents::index_type>
+ consteval _IndexType
+ __static_quotient(_IndexType __nom = numeric_limits<_IndexType>::max())
+ {
+ auto __sta_exts = __static_extents<_Extents>();
+ for (auto __factor : __sta_exts)
+ {
+ if (__factor != dynamic_extent)
+ __nom /= _IndexType(__factor);
+ if (__nom == 0)
+ break;
+ }
+ return __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::mapping<typename _Mapping::extents_type>,
+ _Mapping>;
+
+ template<typename _Mapping>
+ concept __standardized_mapping = __mapping_of<layout_left, _Mapping>
+ || __mapping_of<layout_right, _Mapping>
+ || __mapping_of<layout_stride, _Mapping>;
+
+ // A tag type to create internal ctors.
+ class __internal_ctor
+ { };
+ }
+
+ 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)
+ mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
+ : mapping(__other.extents(), __mdspan::__internal_ctor{})
+ { __glibcxx_assert(*this == __other); }
+
+ 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::__fwd_prod(_M_extents, extents_type::rank()); }
+
+ 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>(__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));
+ }
+
+ [[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;
+ __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)
+ mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
+ : mapping(__other.extents(), __mdspan::__internal_ctor{})
+ { __glibcxx_assert(*this == __other); }
+
+ 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::__fwd_prod(_M_extents, extents_type::rank()); }
+
+ 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>(__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));
+ }
+
+ [[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>
+ 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>());
+ }
+ }
+
+ 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
+ {
+ __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<__mdspan::__valid_index_type<index_type> _OIndexType>
+ 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<__mdspan::__valid_index_type<index_type> _OIndexType>
+ 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(numeric_limits<_OIndexType>::max(),
+ numeric_limits<index_type>::max()))
+ __glibcxx_assert(!cmp_less(numeric_limits<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;
+ }
+
+ 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>(__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())
+ {
+ constexpr auto __rank = extents_type::rank();
+ auto __size = __mdspan::__fwd_prod(_M_extents, __rank);
+ 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:
+ using _S_strides_t = typename __array_traits<index_type,
+ extents_type::rank()>::_Type;
+ [[no_unique_address]] extents_type _M_extents;
+ [[no_unique_address]] _S_strides_t _M_strides;
+ };
+
+ 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; }
+ };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+}
+#endif
+#endif
diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory
index 78a1250..1da03b3 100644
--- a/libstdc++-v3/include/std/memory
+++ b/libstdc++-v3/include/std/memory
@@ -97,6 +97,10 @@
# 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
@@ -105,9 +109,11 @@
#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_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
diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex
index b3f89c0..e575a81 100644
--- a/libstdc++-v3/include/std/mutex
+++ b/libstdc++-v3/include/std/mutex
@@ -733,7 +733,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..cc7af5b 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)
{
@@ -858,6 +864,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 { }
@@ -1158,6 +1168,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
@@ -1772,6 +1809,16 @@ _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;
+
+ 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/ranges b/libstdc++-v3/include/std/ranges
index 9300c36..210ac82 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -5336,7 +5336,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>&>>>;
}
@@ -6598,7 +6598,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,8 +7287,8 @@ 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>
@@ -7743,7 +7743,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 +8303,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); }
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/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/stop_token b/libstdc++-v3/include/std/stop_token
index 1225b3a..775ec6a 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>
@@ -650,6 +649,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
stop_callback(stop_token, _Callback) -> stop_callback<_Callback>;
_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace
-#endif // __cplusplus > 201703L
+} // namespace std
+#endif // __glibcxx_jthread
#endif // _GLIBCXX_STOP_TOKEN
diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index 2e69af1..b39ce71 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -2939,19 +2939,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..0554111 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -280,11 +280,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 +290,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).
@@ -1036,9 +1041,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 +1105,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 +1167,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 +1475,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 +1491,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>
@@ -3212,7 +3243,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 +3298,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 +3612,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 +3645,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 +3694,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 +3758,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;
@@ -4002,7 +4065,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
diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility
index 1c15c75..8a85ccf 100644
--- a/libstdc++-v3/include/std/utility
+++ b/libstdc++-v3/include/std/utility
@@ -201,7 +201,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#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); }