aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/bits
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/include/bits')
-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.h2919
-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/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_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.def82
-rw-r--r--libstdc++-v3/include/bits/version.h92
31 files changed, 6118 insertions, 2343 deletions
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 ace8b9f..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,31 +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
{
- if (_M_spec._M_chrono_specs.empty())
- 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&);
@@ -520,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
- // 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();
const size_t __padwidth = _M_spec._M_get_width(__fc);
if (__padwidth == 0)
- return _M_format_to(__t, __fc.out(), __fc, __is_neg);
+ 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, __is_neg);
+ _M_format_to(__t, __sink.out(), __fc);
return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill);
}
- template<typename _Tp, typename _Out, typename _FormatContext>
- _Out
- _M_format_to(const _Tp& __t, _Out __out, _FormatContext& __fc,
- bool __is_neg) const
+
+ _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())
+ {
+ 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);
+ }
+
+ [[__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;
+ };
+ }
+
+ // 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, &__out] {
- if constexpr (chrono::__is_duration_v<_Tp>
- || __is_specialization_of<_Tp, chrono::hh_mm_ss>)
- if (__is_neg)
+ auto __print_sign = [__is_neg = __t._M_is_neg, &__out] () mutable {
+ if (__is_neg)
{
*__out++ = _S_plus_minus[1];
__is_neg = false;
@@ -557,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%");
@@ -566,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];
@@ -700,134 +1133,37 @@ namespace __format
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);
@@ -840,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];
@@ -861,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).
@@ -933,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.
@@ -1349,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();
- }
+ chrono::hh_mm_ss<chrono::seconds> __hms(__ts);
+ unsigned __mo = 3 + __mod;
- 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;
+ _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());
- __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);
-
- __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".
@@ -1543,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 a hh_mm_ss.
- template<typename _Tp>
- static decltype(auto)
- _S_hms(const _Tp& __t)
+ // 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);
+ }
+ };
+
+ 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);
}
+ };
- // Remove subsecond precision from a time_point.
- template<typename _Tp>
- static auto
- _S_floor_seconds(const _Tp& __t)
+#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(), {}); }
+
+ 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
@@ -1726,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>
@@ -1749,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>
@@ -1766,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>
@@ -1783,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>
@@ -1800,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>
@@ -1817,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>
@@ -1834,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>
@@ -1851,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>
@@ -1868,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>
@@ -1885,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>
@@ -1902,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>
@@ -1919,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>
@@ -1936,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>
@@ -1953,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>
@@ -1970,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>
@@ -1987,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>
@@ -2004,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>
@@ -2021,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
@@ -2039,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>
@@ -2056,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
@@ -2075,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
@@ -2086,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>
@@ -2102,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>
@@ -2136,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>
@@ -2167,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>
@@ -2197,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>
@@ -2234,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
@@ -2252,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>;
@@ -2267,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
@@ -2859,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.
@@ -2870,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;
}
@@ -3039,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))
{
@@ -3098,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))
{
@@ -3352,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).
@@ -3626,7 +4467,7 @@ namespace __detail
}
else
{
- if (_M_need & _ChronoParts::_TimeOfDay)
+ if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
__err |= ios_base::failbit;
break;
}
@@ -3694,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;
}
@@ -3784,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;
}
@@ -3795,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;
}
@@ -3830,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;
}
@@ -4304,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.
@@ -4397,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;
@@ -4405,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;
@@ -4413,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/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_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 2d34a8d..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;
@@ -852,6 +852,14 @@ ftms = {
};
ftms = {
+ name = optional_range_support;
+ values = {
+ v = 202406;
+ cxxmin = 26;
+ };
+};
+
+ftms = {
name = destroying_delete;
values = {
v = 201806;
@@ -1363,7 +1371,7 @@ ftms = {
v = 201907;
cxxmin = 20;
hosted = yes;
- extra_cond = "__glibcxx_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE";
+ extra_cond = "__glibcxx_atomic_wait";
};
};
@@ -1661,6 +1669,14 @@ ftms = {
};
ftms = {
+ name = ranges_starts_ends_with;
+ values = {
+ v = 202106;
+ cxxmin = 23;
+ };
+};
+
+ftms = {
name = constexpr_bitset;
values = {
v = 202202;
@@ -1748,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;
@@ -1952,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 24831f7..dc8ac07 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -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
@@ -1499,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
@@ -1848,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
@@ -1948,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
@@ -2183,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