diff options
Diffstat (limited to 'libstdc++-v3/include')
151 files changed, 14317 insertions, 4590 deletions
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 537774c..0b0cbe2 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -38,6 +38,7 @@ std_freestanding = \ ${std_srcdir}/generator \ ${std_srcdir}/iterator \ ${std_srcdir}/limits \ + ${std_srcdir}/mdspan \ ${std_srcdir}/memory \ ${std_srcdir}/numbers \ ${std_srcdir}/numeric \ @@ -67,6 +68,7 @@ std_headers = \ ${std_srcdir}/codecvt \ ${std_srcdir}/complex \ ${std_srcdir}/condition_variable \ + ${std_srcdir}/debugging \ ${std_srcdir}/deque \ ${std_srcdir}/execution \ ${std_srcdir}/filesystem \ @@ -76,6 +78,7 @@ std_headers = \ ${std_srcdir}/forward_list \ ${std_srcdir}/fstream \ ${std_srcdir}/future \ + ${std_srcdir}/inplace_vector \ ${std_srcdir}/iomanip \ ${std_srcdir}/ios \ ${std_srcdir}/iosfwd \ @@ -188,11 +191,13 @@ bits_headers = \ ${bits_srcdir}/basic_ios.tcc \ ${bits_srcdir}/basic_string.h \ ${bits_srcdir}/basic_string.tcc \ + ${bits_srcdir}/binders.h \ ${bits_srcdir}/charconv.h \ ${bits_srcdir}/chrono.h \ ${bits_srcdir}/chrono_io.h \ ${bits_srcdir}/codecvt.h \ ${bits_srcdir}/cow_string.h \ + ${bits_srcdir}/cpyfunc_impl.h \ ${bits_srcdir}/deque.tcc \ ${bits_srcdir}/erase_if.h \ ${bits_srcdir}/formatfwd.h \ @@ -203,10 +208,13 @@ bits_headers = \ ${bits_srcdir}/fs_ops.h \ ${bits_srcdir}/fs_path.h \ ${bits_srcdir}/fstream.tcc \ + ${bits_srcdir}/funcref_impl.h \ + ${bits_srcdir}/funcwrap.h \ ${bits_srcdir}/gslice.h \ ${bits_srcdir}/gslice_array.h \ ${bits_srcdir}/hashtable.h \ ${bits_srcdir}/hashtable_policy.h \ + ${bits_srcdir}/indirect.h \ ${bits_srcdir}/indirect_array.h \ ${bits_srcdir}/ios_base.h \ ${bits_srcdir}/istream.tcc \ @@ -222,7 +230,6 @@ bits_headers = \ ${bits_srcdir}/mask_array.h \ ${bits_srcdir}/memory_resource.h \ ${bits_srcdir}/mofunc_impl.h \ - ${bits_srcdir}/move_only_function.h \ ${bits_srcdir}/new_allocator.h \ ${bits_srcdir}/node_handle.h \ ${bits_srcdir}/ostream.tcc \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 7b96b22..e3a6d5f 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -396,6 +396,7 @@ std_freestanding = \ ${std_srcdir}/generator \ ${std_srcdir}/iterator \ ${std_srcdir}/limits \ + ${std_srcdir}/mdspan \ ${std_srcdir}/memory \ ${std_srcdir}/numbers \ ${std_srcdir}/numeric \ @@ -423,6 +424,7 @@ std_freestanding = \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/codecvt \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/complex \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/condition_variable \ +@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/debugging \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/deque \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/execution \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/filesystem \ @@ -432,6 +434,7 @@ std_freestanding = \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/forward_list \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/fstream \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/future \ +@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/inplace_vector \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/iomanip \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/ios \ @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/iosfwd \ @@ -541,11 +544,13 @@ bits_freestanding = \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/basic_ios.tcc \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/basic_string.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/basic_string.tcc \ +@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/binders.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/charconv.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/chrono.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/chrono_io.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/codecvt.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/cow_string.h \ +@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/cpyfunc_impl.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/deque.tcc \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/erase_if.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/formatfwd.h \ @@ -556,10 +561,13 @@ bits_freestanding = \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/fs_ops.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/fs_path.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/fstream.tcc \ +@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/funcref_impl.h \ +@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/funcwrap.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/gslice.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/gslice_array.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/hashtable.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/hashtable_policy.h \ +@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/indirect.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/indirect_array.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/ios_base.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/istream.tcc \ @@ -575,7 +583,6 @@ bits_freestanding = \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/mask_array.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/memory_resource.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/mofunc_impl.h \ -@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/move_only_function.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/new_allocator.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/node_handle.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/ostream.tcc \ diff --git a/libstdc++-v3/include/bits/align.h b/libstdc++-v3/include/bits/align.h index 2b40c37..6a85244 100644 --- a/libstdc++-v3/include/bits/align.h +++ b/libstdc++-v3/include/bits/align.h @@ -102,6 +102,23 @@ align(size_t __align, size_t __size, void*& __ptr, size_t& __space) noexcept } #endif // __glibcxx_assume_aligned +#ifdef __glibcxx_is_sufficiently_aligned // C++ >= 26 + /** @brief Is `__ptr` aligned to an _Align byte boundary? + * + * @tparam _Align An alignment value + * @tparam _Tp An object type + * + * C++26 20.2.5 [ptr.align] + * + * @ingroup memory + */ + template<size_t _Align, class _Tp> + [[nodiscard,__gnu__::__always_inline__]] + inline bool + is_sufficiently_aligned(_Tp* __ptr) + { return reinterpret_cast<__UINTPTR_TYPE__>(__ptr) % _Align == 0; } +#endif // __glibcxx_is_sufficiently_aligned + _GLIBCXX_END_NAMESPACE_VERSION } // namespace 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 c90bd09..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; } @@ -3938,21 +3938,23 @@ _GLIBCXX_END_NAMESPACE_CXX11 operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs, basic_string<_CharT, _Traits, _Alloc>&& __rhs) { -#if _GLIBCXX_USE_CXX11_ABI - using _Alloc_traits = allocator_traits<_Alloc>; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + // Return value must use __lhs.get_allocator(), but if __rhs has equal + // allocator then we can choose which parameter to modify in-place. bool __use_rhs = false; - if _GLIBCXX17_CONSTEXPR (typename _Alloc_traits::is_always_equal{}) + if constexpr (allocator_traits<_Alloc>::is_always_equal::value) __use_rhs = true; else if (__lhs.get_allocator() == __rhs.get_allocator()) __use_rhs = true; if (__use_rhs) -#endif { const auto __size = __lhs.size() + __rhs.size(); if (__size > __lhs.capacity() && __size <= __rhs.capacity()) return std::move(__rhs.insert(0, __lhs)); } return std::move(__lhs.append(__rhs)); +#pragma GCC diagnostic pop } template<typename _CharT, typename _Traits, typename _Alloc> diff --git a/libstdc++-v3/include/bits/binders.h b/libstdc++-v3/include/bits/binders.h new file mode 100644 index 0000000..6489edd --- /dev/null +++ b/libstdc++-v3/include/bits/binders.h @@ -0,0 +1,234 @@ +// 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/binder.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{functional} + */ + +#ifndef _GLIBCXX_BINDERS_H +#define _GLIBCXX_BINDERS_H 1 + +#ifdef _GLIBCXX_SYSHDR +#pragma GCC system_header +#endif + +#if __cplusplus >= 202002L + +#include <bits/invoke.h> +#include <bits/move.h> + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template<size_t, typename _Tp> + struct _Indexed_bound_arg + { + [[no_unique_address]] _Tp _M_val; + }; + + template<typename... _IndexedArgs> + struct _Bound_arg_storage : _IndexedArgs... + { + template<bool _Back, typename _Fd, typename _Self, typename... _CallArgs> + static constexpr + decltype(auto) + _S_apply(_Fd&& __fd, _Self&& __self, _CallArgs&&... __call_args) + { + if constexpr (_Back) + return std::__invoke(std::forward<_Fd>(__fd), + std::forward<_CallArgs>(__call_args)..., + __like_t<_Self, _IndexedArgs>(__self)._M_val...); + else + return std::__invoke(std::forward<_Fd>(__fd), + __like_t<_Self, _IndexedArgs>(__self)._M_val..., + std::forward<_CallArgs>(__call_args)...); + } + }; + + template<typename... _BoundArgs, typename... _Args> + constexpr auto + __make_bound_args(_Args&&... __args) + { + if constexpr (sizeof...(_BoundArgs) == 1) + // pack has one element, so return copy of arg + return (_BoundArgs(std::forward<_Args>(__args)), ...); + else + { + auto __impl = [&]<size_t... _Inds>(index_sequence<_Inds...>) + { + return _Bound_arg_storage<_Indexed_bound_arg<_Inds, _BoundArgs>...> + { {_BoundArgs(std::forward<_Args>(__args))}... }; + }; + return __impl(index_sequence_for<_BoundArgs...>()); + } + } + + template<bool _Back, typename _Fd, typename... _BoundArgs> + class _Binder + { + template<typename _Self, typename... _CallArgs> + using _Result_t = __conditional_t< + _Back, + invoke_result<__like_t<_Self, _Fd>, + _CallArgs..., __like_t<_Self, _BoundArgs>...>, + invoke_result<__like_t<_Self, _Fd>, + __like_t<_Self, _BoundArgs>..., _CallArgs...>>::type; + + template<typename _Self, typename... _CallArgs> + static consteval bool + _S_noexcept_invocable() + { + if constexpr (_Back) + return is_nothrow_invocable_v< __like_t<_Self, _Fd>, + _CallArgs..., __like_t<_Self, _BoundArgs>...>; + else + return is_nothrow_invocable_v<__like_t<_Self, _Fd>, + __like_t<_Self, _BoundArgs>..., _CallArgs...>; + } + + public: + static_assert(is_move_constructible_v<_Fd>); + static_assert((is_move_constructible_v<_BoundArgs> && ...)); + + // First parameter is to ensure this constructor is never used + // instead of the copy/move constructor. + template<typename _Fn, typename... _Args> + explicit constexpr + _Binder(int, _Fn&& __fn, _Args&&... __args) + noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>, + is_nothrow_constructible<_BoundArgs, _Args>...>::value) + : _M_fd(std::forward<_Fn>(__fn)), + _M_bound_args(__make_bound_args<_BoundArgs...>(std::forward<_Args>(__args)...)) + { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); } + +#if __cpp_explicit_this_parameter + template<typename _Self, typename... _CallArgs> + constexpr _Result_t<_Self, _CallArgs...> + operator()(this _Self&& __self, _CallArgs&&... __call_args) + noexcept(_S_noexcept_invocable<_Self, _CallArgs...>()) + { + return _S_call(__like_t<_Self, _Binder>(__self), + std::forward<_CallArgs>(__call_args)...); + } +#else + template<typename... _CallArgs> + requires true + constexpr _Result_t<_Binder&, _CallArgs...> + operator()(_CallArgs&&... __call_args) & + noexcept(_S_noexcept_invocable<_Binder&, _CallArgs...>()) + { + return _S_call(*this, std::forward<_CallArgs>(__call_args)...); + } + + template<typename... _CallArgs> + requires true + constexpr _Result_t<const _Binder&, _CallArgs...> + operator()(_CallArgs&&... __call_args) const & + noexcept(_S_noexcept_invocable<const _Binder&, _CallArgs...>()) + { + return _S_call(*this, std::forward<_CallArgs>(__call_args)...); + } + + template<typename... _CallArgs> + requires true + constexpr _Result_t<_Binder&&, _CallArgs...> + operator()(_CallArgs&&... __call_args) && + noexcept(_S_noexcept_invocable<_Binder&&, _CallArgs...>()) + { + return _S_call(std::move(*this), + std::forward<_CallArgs>(__call_args)...); + } + + template<typename... _CallArgs> + requires true + constexpr _Result_t<const _Binder&&, _CallArgs...> + operator()(_CallArgs&&... __call_args) const && + noexcept(_S_noexcept_invocable<const _Binder&&, _CallArgs...>()) + { + return _S_call(std::move(*this), + std::forward<_CallArgs>(__call_args)...); + } + + template<typename... _CallArgs> + void operator()(_CallArgs&&...) & = delete; + + template<typename... _CallArgs> + void operator()(_CallArgs&&...) const & = delete; + + template<typename... _CallArgs> + void operator()(_CallArgs&&...) && = delete; + + template<typename... _CallArgs> + void operator()(_CallArgs&&...) const && = delete; +#endif + + template<typename _Tp, typename... _CallArgs> + static constexpr + decltype(auto) + _S_call(_Tp&& __g, _CallArgs&&... __call_args) + { + if constexpr (sizeof...(_BoundArgs) > 1) + return _BoundArgsStorage::template _S_apply<_Back>( + std::forward<_Tp>(__g)._M_fd, + std::forward<_Tp>(__g)._M_bound_args, + std::forward<_CallArgs>(__call_args)...); + else if constexpr (sizeof...(_BoundArgs) == 0) + return std::__invoke(std::forward<_Tp>(__g)._M_fd, + std::forward<_CallArgs>(__call_args)...); + else if constexpr (_Back) // sizeof...(_BoundArgs) == 1 + return std::__invoke(std::forward<_Tp>(__g)._M_fd, + std::forward<_CallArgs>(__call_args)..., + std::forward<_Tp>(__g)._M_bound_args); + else // !_Back && sizeof...(_BoundArgs) == 1 + return std::__invoke(std::forward<_Tp>(__g)._M_fd, + std::forward<_Tp>(__g)._M_bound_args, + std::forward<_CallArgs>(__call_args)...); + } + + private: + using _BoundArgsStorage + // _BoundArgs are required to be move-constructible, so this is valid. + = decltype(__make_bound_args<_BoundArgs...>(std::declval<_BoundArgs>()...)); + + [[no_unique_address]] _Fd _M_fd; + [[no_unique_address]] _BoundArgsStorage _M_bound_args; + }; + + template<typename _Fn, typename... _Args> + using _Bind_front_t = _Binder<false, decay_t<_Fn>, decay_t<_Args>...>; + + // for zero bounds args behavior of bind_front and bind_back is the same, + // so reuse _Bind_front_t, i.e. _Binder<false, ...> + template<typename _Fn, typename... _Args> + using _Bind_back_t + = _Binder<(sizeof...(_Args) > 0), decay_t<_Fn>, decay_t<_Args>...>; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // __cplusplus >= 202002L +#endif // _GLIBCXX_BINDERS_H 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/char_traits.h b/libstdc++-v3/include/bits/char_traits.h index 67e18e8..5ca3466 100644 --- a/libstdc++-v3/include/bits/char_traits.h +++ b/libstdc++-v3/include/bits/char_traits.h @@ -284,7 +284,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif - if _GLIBCXX17_CONSTEXPR (sizeof(_CharT) == 1 && __is_trivial(_CharT)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + if _GLIBCXX_CONSTEXPR (sizeof(_CharT) == 1 && __is_trivial(_CharT)) { if (__n) { @@ -298,6 +300,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION for (std::size_t __i = 0; __i < __n; ++__i) __s[__i] = __a; } +#pragma GCC diagnostic pop return __s; } diff --git a/libstdc++-v3/include/bits/chrono.h b/libstdc++-v3/include/bits/chrono.h index fad2162..8de8e75 100644 --- a/libstdc++-v3/include/bits/chrono.h +++ b/libstdc++-v3/include/bits/chrono.h @@ -1244,6 +1244,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2) now() noexcept; // Map to C API + [[__gnu__::__always_inline__]] static std::time_t to_time_t(const time_point& __t) noexcept { @@ -1251,6 +1252,7 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2) (__t.time_since_epoch()).count()); } + [[__gnu__::__always_inline__]] static time_point from_time_t(std::time_t __t) noexcept { diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index b7f6f5f..809d795 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,353 @@ 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 if parts that are checked for ok come directly from the + // input, instead of being computed. + unsigned _M_needs_ok_check : 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,16 +554,32 @@ 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{}; - - auto __finalize = [this, &__spec] { + _ChronoSpec<_CharT> __spec = __def; + + auto __finalize = [this, &__spec, &__def] { + using enum _ChronoParts; + _ChronoParts __checked + = __spec._M_debug ? _YearMonthDay|_IndexedWeekday + : _Month|_Weekday; + // n.b. for calendar types __def._M_needed contains only parts + // copied from the input, remaining ones are computed, and thus ok + __spec._M_needs_ok_check + = __spec._M_needs(__def._M_needed & __checked); _M_spec = __spec; }; @@ -284,13 +603,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 +639,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 +651,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 +675,7 @@ namespace __format __locale_specific = true; break; case 'c': - __needed = _DateTime; + __needed = _Date|_HoursMinutesSeconds; __allowed_mods = _Mod_E; __locale_specific = true; break; @@ -358,27 +690,30 @@ 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 = __parts & _DayOfYear; + // If we do not know day-of-year then we must have a duration, + // which is to be formatted as decimal number of days. + if (__needed == _None) + __needed = _HoursMinutesSeconds; 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 +721,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 +744,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 +753,7 @@ namespace __format __allowed_mods = _Mod_E; break; case 'X': - __needed = _TimeOfDay; + __needed = _HoursMinutesSeconds; __locale_specific = true; __allowed_mods = _Mod_E; break; @@ -427,11 +766,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 +798,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('%'); @@ -485,36 +830,25 @@ namespace __format __throw_format_error("chrono format error: unescaped '%' in " "chrono-specs"); - _M_spec = __spec; - _M_spec._M_chrono_specs - = __string_view(__chrono_specs, __first - __chrono_specs); - _M_spec._M_locale_specific(__locale_specific); + __spec._M_chrono_specs + = __string_view(__chrono_specs, __first - __chrono_specs); + __finalize(); return __first; } - // TODO this function template is instantiated for every different _Tp. - // Consider creating a polymorphic interface for calendar types so - // that we instantiate fewer different specializations. Similar to - // _Sink_iter for std::format. Replace each _S_year, _S_day etc. with - // member functions of that type. - template<typename _Tp, typename _FormatContext> + // pre: !_M_spec._M_chrono_specs.empty() + template<typename _FormatContext> typename _FormatContext::iterator - _M_format(const _Tp& __t, _FormatContext& __fc, - bool __is_neg = false) const + _M_format(const _ChronoData<_CharT>& __t, _FormatContext& __fc) const { - auto __first = _M_spec._M_chrono_specs.begin(); - const auto __last = _M_spec._M_chrono_specs.end(); - if (__first == __last) - return _M_format_to_ostream(__t, __fc, __is_neg); - #if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8 // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3565. Handling of encodings in localized formatting // of chrono types is underspecified if constexpr (is_same_v<_CharT, char>) if constexpr (__unicode::__literal_encoding_is_utf8()) - if (_M_spec._M_localized && _M_spec._M_locale_specific()) + if (_M_spec._M_localized && _M_spec._M_locale_specific) { extern locale __with_encoding_conversion(const locale&); @@ -522,36 +856,208 @@ namespace __format // in the locale's encoding to UTF-8. locale __loc = __fc.locale(); if (__loc != locale::classic()) - __fc._M_loc = __with_encoding_conversion(__loc); + __fc._M_loc = __with_encoding_conversion(__loc); } #endif - _Sink_iter<_CharT> __out; - __format::_Str_sink<_CharT> __sink; - bool __write_direct = false; - if constexpr (is_same_v<typename _FormatContext::iterator, - _Sink_iter<_CharT>>) - { - if (_M_spec._M_width_kind == __format::_WP_none) + const size_t __padwidth = _M_spec._M_get_width(__fc); + if (__padwidth == 0) + return _M_format_to(__t, __fc.out(), __fc); + + using _Out = typename _FormatContext::iterator; + _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth); + _M_format_to(__t, __sink.out(), __fc); + return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill); + } + + + _ChronoSpec<_CharT> _M_spec; + + protected: + static constexpr const _CharT* _S_chars + = _GLIBCXX_WIDEN("0123456789.Lf:/ +-{}"); + static constexpr _CharT _S_dot = _S_chars[10]; + static constexpr _CharT _S_colon = _S_chars[13]; + static constexpr _CharT _S_slash = _S_chars[14]; + static constexpr _CharT _S_space = _S_chars[15]; + static constexpr const _CharT* _S_fp_fmt = _S_chars + 11; + static constexpr const _CharT* _S_plus_minus = _S_chars + 16; + static constexpr const _CharT* _S_minus_empty_spec = _S_chars + 17; + static constexpr const _CharT* _S_empty_spec = _S_chars + 18; + + [[__gnu__::__always_inline__]] + static _Runtime_format_string<_CharT> + _S_empty_fs() + { return _Runtime_format_string<_CharT>(_S_empty_spec); } + + static constexpr const _CharT* _S_weekdays[] + { + _GLIBCXX_WIDEN("Sunday"), + _GLIBCXX_WIDEN("Monday"), + _GLIBCXX_WIDEN("Tuesday"), + _GLIBCXX_WIDEN("Wednesday"), + _GLIBCXX_WIDEN("Thursday"), + _GLIBCXX_WIDEN("Friday"), + _GLIBCXX_WIDEN("Saturday"), + }; + + static constexpr const _CharT* _S_months[] + { + _GLIBCXX_WIDEN("January"), + _GLIBCXX_WIDEN("February"), + _GLIBCXX_WIDEN("March"), + _GLIBCXX_WIDEN("April"), + _GLIBCXX_WIDEN("May"), + _GLIBCXX_WIDEN("June"), + _GLIBCXX_WIDEN("July"), + _GLIBCXX_WIDEN("August"), + _GLIBCXX_WIDEN("September"), + _GLIBCXX_WIDEN("October"), + _GLIBCXX_WIDEN("November"), + _GLIBCXX_WIDEN("December"), + }; + + private: + template<typename _OutIter> + _OutIter + _M_write(_OutIter __out, const locale& __loc, __string_view __s) const + { +#if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8 + __sso_string __buf; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3565. Handling of encodings in localized formatting + // of chrono types is underspecified + if constexpr (is_same_v<_CharT, char>) + if constexpr (__unicode::__literal_encoding_is_utf8()) + if (_M_spec._M_localized && _M_spec._M_locale_specific + && __loc != locale::classic()) { - __out = __fc.out(); - __write_direct = true; + extern string_view + __locale_encoding_to_utf8(const locale&, string_view, void*); + + __s = __locale_encoding_to_utf8(__loc, __s, &__buf); } - else - __out = __sink.out(); +#endif + return __format::__write(std::move(__out), __s); + } + + [[__gnu__::__always_inline__]] + static bool + _S_localized_spec(_CharT __conv, _CharT __mod) + { + switch (__conv) + { + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'h': + case 'p': + 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; + } + + __string_view + _M_check_ok(const _ChronoData<_CharT>& __t, _CharT& __conv) const + { + if (!_M_spec._M_debug) + { + switch (__conv) + { + case 'a': + case 'A': + if (!__t._M_weekday.ok()) [[unlikely]] + __throw_format_error("format error: invalid weekday"); + break; + case 'b': + case 'h': + case 'B': + if (!__t._M_month.ok()) [[unlikely]] + __throw_format_error("format error: invalid month"); + break; + default: + break; } - else - __out = __sink.out(); + return __string_view(); + } - // 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(); + switch (__conv) + { + // %\0 is extension for handling weekday index + case '\0': + if (__t._M_weekday_index < 1 || __t._M_weekday_index > 5) [[unlikely]] + return _GLIBCXX_WIDEN("index"); + break; + case 'a': + case 'A': + if (!__t._M_weekday.ok()) [[unlikely]] + { + __conv = 'w'; // print as decimal number + return _GLIBCXX_WIDEN("weekday"); + } + break; + case 'b': + case 'h': + case 'B': + if (!__t._M_month.ok()) [[unlikely]] + { + __conv = 'm'; // print as decimal number + return _GLIBCXX_WIDEN("month"); + } + break; + case 'd': + case 'e': + if (!__t._M_day.ok()) [[unlikely]] + return _GLIBCXX_WIDEN("day"); + break; + case 'F': + if (!(__t._M_year/__t._M_month/__t._M_day).ok()) [[unlikely]] + return _GLIBCXX_WIDEN("date"); + break; + case 'Y': + if (!__t._M_year.ok()) [[unlikely]] + return _GLIBCXX_WIDEN("year"); + break; + default: + break; + } + return __string_view(); + } - auto __print_sign = [&__is_neg, &__out] { - if constexpr (chrono::__is_duration_v<_Tp> - || __is_specialization_of<_Tp, chrono::hh_mm_ss>) - if (__is_neg) + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_format_to(const _ChronoData<_CharT>& __t, _OutIter __out, + _FormatContext& __fc) const + { + auto __first = _M_spec._M_chrono_specs.begin(); + const auto __last = _M_spec._M_chrono_specs.end(); + + auto __print_sign = [__is_neg = __t._M_is_neg, &__out] () mutable { + if (__is_neg) { *__out++ = _S_plus_minus[1]; __is_neg = false; @@ -559,6 +1065,36 @@ namespace __format return std::move(__out); }; + struct tm __tm{}; + bool __use_locale_fmt = false; + if (_M_spec._M_localized && _M_spec._M_locale_specific) + if (__fc.locale() != locale::classic()) + { + __use_locale_fmt = true; + + __tm.tm_year = (int)__t._M_year - 1900; + __tm.tm_yday = __t._M_day_of_year.count(); + __tm.tm_mon = (unsigned)__t._M_month - 1; + __tm.tm_mday = (unsigned)__t._M_day; + __tm.tm_wday = __t._M_weekday.c_encoding(); + __tm.tm_hour = __t._M_hours.count(); + __tm.tm_min = __t._M_minutes.count(); + __tm.tm_sec = __t._M_seconds.count(); + + // Some locales use %Z in their %c format but we don't want strftime + // to use the system's local time zone (from /etc/localtime or $TZ) + // as the output for %Z. Setting tm_isdst to -1 says there is no + // time zone info available for the time in __tm. + __tm.tm_isdst = -1; + +#ifdef _GLIBCXX_USE_STRUCT_TM_TM_ZONE + // POSIX.1-2024 adds tm.tm_zone which will be used for %Z. + // BSD has had tm_zone since 1987 but as char* so cast away const. + if (__t._M_zone_cstr) + __tm.tm_zone = const_cast<char*>(__t._M_zone_cstr); +#endif + } + // Characters to output for "%n", "%t" and "%%" specifiers. constexpr const _CharT* __literals = _GLIBCXX_WIDEN("\n\t%"); @@ -568,100 +1104,101 @@ namespace __format do { _CharT __c = *__first++; - switch (__c) + __string_view __invalid; + if (_M_spec._M_needs_ok_check) + __invalid = _M_check_ok(__t, __c); + + if (__invalid.empty() &&__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), __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), __c == 'B'); break; case 'c': - __out = _M_c(__t, std::move(__out), __fc, __mod == 'E'); + __out = _M_c(__t, std::move(__out)); 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)); 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); + __out = _M_r(__t, __print_sign()); 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]; @@ -680,6 +1217,14 @@ namespace __format __first = __last; break; } + + if (!__invalid.empty()) + { + constexpr __string_view __pref = _GLIBCXX_WIDEN(" is not a valid "); + __out = __format::__write(std::move(__out), __pref); + __out = __format::__write(std::move(__out), __invalid); + } + __mod = _CharT(); // Scan for next '%' and write out everything before it. __string_view __str(__first, __last - __first); @@ -699,241 +1244,64 @@ namespace __format } } while (__first != __last); - - if constexpr (is_same_v<typename _FormatContext::iterator, - _Sink_iter<_CharT>>) - if (__write_direct) - return __out; - - auto __str = std::move(__sink).get(); - return __format::__write_padded_as_spec(__str, __str.size(), - __fc, _M_spec); + return std::move(__out); } - _ChronoSpec<_CharT> _M_spec; - - private: - // Return the formatting locale. - template<typename _FormatContext> - std::locale - _M_locale(_FormatContext& __fc) const - { - if (!_M_spec._M_localized) - return std::locale::classic(); - else - return __fc.locale(); - } - - // Format for empty chrono-specs, e.g. "{}" (C++20 [time.format] p6). - // TODO: consider moving body of every operator<< into this function - // and use std::format("{}", t) to implement those operators. That - // would avoid std::format("{}", t) calling operator<< which calls - // std::format again. - template<typename _Tp, typename _FormatContext> - typename _FormatContext::iterator - _M_format_to_ostream(const _Tp& __t, _FormatContext& __fc, - bool __is_neg) const - { - using ::std::chrono::__detail::__utc_leap_second; - using ::std::chrono::__detail::__local_time_fmt; - - basic_ostringstream<_CharT> __os; - __os.imbue(_M_locale(__fc)); - - if constexpr (__is_specialization_of<_Tp, __local_time_fmt>) - { - // Format as "{:L%F %T}" - auto __days = chrono::floor<chrono::days>(__t._M_time); - __os << chrono::year_month_day(__days) << ' ' - << chrono::hh_mm_ss(__t._M_time - __days); - - // For __local_time_fmt the __is_neg flags says whether to - // append " %Z" to the result. - if (__is_neg) - { - if (!__t._M_abbrev) [[unlikely]] - __format::__no_timezone_available(); - else if constexpr (is_same_v<_CharT, char>) - __os << ' ' << *__t._M_abbrev; - else - { - __os << L' '; - for (char __c : *__t._M_abbrev) - __os << __c; - } - } - } - else - { - if constexpr (__is_specialization_of<_Tp, __utc_leap_second>) - __os << __t._M_date << ' ' << __t._M_time; - else if constexpr (chrono::__is_time_point_v<_Tp>) - { - // Need to be careful here because not all specializations - // of chrono::sys_time can be written to an ostream. - // For the specializations of time_point that can be - // formatted with an empty chrono-specs, either it's a - // sys_time with period greater or equal to days: - if constexpr (is_convertible_v<_Tp, chrono::sys_days>) - __os << _S_date(__t); - else // Or it's formatted as "{:L%F %T}": - { - auto __days = chrono::floor<chrono::days>(__t); - __os << chrono::year_month_day(__days) << ' ' - << chrono::hh_mm_ss(__t - __days); - } - } - else - { - if constexpr (chrono::__is_duration_v<_Tp>) - if (__is_neg) [[unlikely]] - __os << _S_plus_minus[1]; - __os << __t; - } - } - - auto __str = std::move(__os).str(); - return __format::__write_padded_as_spec(__str, __str.size(), - __fc, _M_spec); - } - - static constexpr const _CharT* _S_chars - = _GLIBCXX_WIDEN("0123456789+-:/ {}"); - static constexpr const _CharT* _S_plus_minus = _S_chars + 10; - static constexpr _CharT _S_colon = _S_chars[12]; - static constexpr _CharT _S_slash = _S_chars[13]; - static constexpr _CharT _S_space = _S_chars[14]; - static constexpr const _CharT* _S_empty_spec = _S_chars + 15; - template<typename _OutIter> _OutIter - _M_write(_OutIter __out, const locale& __loc, __string_view __s) const + _M_wi(unsigned __wi, _OutIter __out) const { -#if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8 - __sso_string __buf; - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 3565. Handling of encodings in localized formatting - // of chrono types is underspecified - if constexpr (is_same_v<_CharT, char>) - if constexpr (__unicode::__literal_encoding_is_utf8()) - if (_M_spec._M_localized && _M_spec._M_locale_specific() - && __loc != locale::classic()) - { - extern string_view - __locale_encoding_to_utf8(const locale&, string_view, void*); - - __s = __locale_encoding_to_utf8(__loc, __s, &__buf); - } -#endif - return __format::__write(std::move(__out), __s); + // %\0 Extension to format weekday index, used only by empty format spec + _CharT __buf[3]; + __out = __format::__write(std::move(__out), _S_str_d1(__buf, __wi)); + return std::move(__out); } - template<typename _Tp, typename _FormatContext> - typename _FormatContext::iterator - _M_a_A(const _Tp& __t, typename _FormatContext::iterator __out, - _FormatContext& __ctx, bool __full) const + template<typename _OutIter> + _OutIter + _M_a_A(chrono::weekday __wd, _OutIter __out, 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"); - - locale __loc = _M_locale(__ctx); - const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); - const _CharT* __days[7]; - if (__full) - __tp._M_days(__days); - else - __tp._M_days_abbreviated(__days); - __string_view __str(__days[__wd.c_encoding()]); - return _M_write(std::move(__out), __loc, __str); + __string_view __str = _S_weekdays[__wd.c_encoding()]; + if (!__full) + __str = __str.substr(0, 3); + return __format::__write(std::move(__out), __str); } - template<typename _Tp, typename _FormatContext> - typename _FormatContext::iterator - _M_b_B(const _Tp& __t, typename _FormatContext::iterator __out, - _FormatContext& __ctx, bool __full) const + template<typename _OutIter> + _OutIter + _M_b_B(chrono::month __m, _OutIter __out, 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"); - locale __loc = _M_locale(__ctx); - const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); - const _CharT* __months[12]; - if (__full) - __tp._M_months(__months); - else - __tp._M_months_abbreviated(__months); - __string_view __str(__months[(unsigned)__m - 1]); - return _M_write(std::move(__out), __loc, __str); + __string_view __str = _S_months[(unsigned)__m - 1]; + if (!__full) + __str = __str.substr(0, 3); + return __format::__write(std::move(__out), __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> + _OutIter + _M_c(const _ChronoData<_CharT>& __t, _OutIter __out) 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), false); + *__out = _S_space; + __out = _M_b_B(__t._M_month, std::move(++__out), false); + *__out = _S_space; + __out = _M_d_e(__t._M_day, std::move(++__out), 'e'); + *__out = _S_space; + __out = _M_R_X(__t, std::move(++__out), true); + *__out = _S_space; + return _M_C_y_Y(__t._M_year, std::move(++__out), 'Y'); } - template<typename _Tp, typename _FormatContext> - typename _FormatContext::iterator - _M_C_y_Y(const _Tp& __t, typename _FormatContext::iterator __out, - _FormatContext& __ctx, _CharT __conv, _CharT __mod = 0) const + template<typename _OutIter> + _OutIter + _M_C_y_Y(chrono::year __y, _OutIter __out, _CharT __conv) const { // %C Year divided by 100 using floored division. // %EC Locale's alternative preresentation of the century (era name). @@ -943,414 +1311,407 @@ 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)); + 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); + 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); + } + + 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_needs(_ChronoParts::_DayOfYear)) + { + // 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 (__i == 0 && _M_spec._M_debug) [[unlikely]] + // 0 should not be padded to two digits + return __format::__write(std::move(__out), _S_digit(0)); - 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> + _OutIter + _M_p(chrono::hours __h, _OutIter __out) const { // %p The locale's equivalent of the AM/PM designations. - auto __hms = _S_hms(__t); - 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]); + + _CharT __buf[2]; + _S_fill_ampm(__buf, __h); + return __format::__write(std::move(__out), __string_view(__buf, 2)); } - 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, - _FormatContext& __ctx) const + template<typename _OutIter> + _OutIter + _M_r(const _ChronoData<_CharT>& __t, _OutIter __out) 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[11]; + __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()); + _S_fill_ampm(__buf + 9, __t._M_hours); + + return __format::__write(std::move(__out), __string_view(__buf, 11)); } - 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) [[unlikely]] + { + auto __loc = __ctx.locale(); + 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) [[unlikely]] + std::vformat_to(__sink.out(), __ctx.locale(), + _GLIBCXX_WIDEN("{1:0.{2}Lf}"), __t._M_ereps); else - { - const auto& __np - = use_facet<numpunct<_CharT>>(__loc); - __out = __format::__write(std::move(__out), - _S_two_digits(__s.count())); - *__out++ = __np.decimal_point(); - if constexpr (is_integral_v<rep>) - __out = std::format_to(std::move(__out), - _GLIBCXX_WIDEN("{:0{}}"), - __ss.count(), - __hms.fractional_width); - else - { - auto __str = std::format(_S_empty_spec, __ss.count()); - __out = std::format_to(_GLIBCXX_WIDEN("{:0>{}s}"), - __str, - __hms.fractional_width); - } - } + std::vformat_to(__sink.out(), + _GLIBCXX_WIDEN("{1:0.{2}f}"), __t._M_ereps); + + auto __sv = __sink.view(); + // Skip leading zero and dot + __sv.remove_prefix(2); + return __format::__write(std::move(__out), __sv); } - return __out; + + constexpr unsigned __max_prec = _ChronoData<_CharT>::_S_max_prec; + constexpr typename _ChronoData<_CharT>::_Attoseconds::rep __pow10t[] + { + 1u, + 10u, 100u, 1000u, + 10'000u, 100'000u, 1000'000u, + 10'000'000u, 100'000'000u, 1000'000'000u, + 10'000'000'000u, 100'000'000'000u, 1000'000'000'000u, + 10'000'000'000'000u, 100'000'000'000'000u, 1000'000'000'000'000u, + 10'000'000'000'000'000u, 100'000'000'000'000'000u, 1000'000'000'000'000'000u, + }; + + auto __subs = __t._M_subseconds.count(); + if (__prec < __max_prec) + __subs /= __pow10t[__max_prec - __prec]; + else if (__prec > __max_prec) + __prec = __max_prec; + + using _FmtStr = _Runtime_format_string<_CharT>; + return std::format_to(__out, _FmtStr(_GLIBCXX_WIDEN("{0:0{1}}")), + __subs, __prec); } // %t handled in _M_format - template<typename _Tp, typename _FormatContext> - typename _FormatContext::iterator - _M_u_w(const _Tp& __t, typename _FormatContext::iterator __out, - _FormatContext& __ctx, _CharT __conv, bool __mod = false) const + template<typename _OutIter, typename _FormatContext> + _OutIter + _M_T(const _ChronoData<_CharT>& __t, _OutIter __out, + _FormatContext& __ctx) const + { + // %T Equivalent to %H:%M:%S, with subseconds + __out = _M_R_X(__t, std::move(__out), true); + return _M_subsecs(__t, std::move(__out), __ctx); + } + + template<typename _OutIter> + _OutIter + _M_u_w(chrono::weekday __wd, _OutIter __out, _CharT __conv) const { // %u ISO weekday as a decimal number (1-7), where Monday is 1. // %Ou Locale's alternative numeric rep. // %w Weekday as a decimal number (0-6), where Sunday is 0. // %Ow Locale's alternative numeric rep. - - chrono::weekday __wd = _S_weekday(__t); - - if (__mod && _M_spec._M_localized) [[unlikely]] - if (auto __loc = __ctx.locale(); __loc != locale::classic()) - { - struct tm __tm{}; - __tm.tm_wday = __wd.c_encoding(); - return _M_locale_fmt(std::move(__out), __loc, __tm, - (char)__conv, 'O'); - } - unsigned __wdi = __conv == 'u' ? __wd.iso_encoding() : __wd.c_encoding(); - const _CharT __d = _S_digit(__wdi); - return __format::__write(std::move(__out), __string_view(&__d, 1)); + _CharT __buf[3]; + return __format::__write(std::move(__out), _S_str_d1(__buf, __wdi)); } - template<typename _Tp, typename _FormatContext> - typename _FormatContext::iterator - _M_U_V_W(const _Tp& __t, typename _FormatContext::iterator __out, - _FormatContext& __ctx, _CharT __conv, bool __mod = false) const + template<typename _OutIter> + _OutIter + _M_U_V_W(const _ChronoData<_CharT>& __t, _OutIter __out, + _CharT __conv) const { // %U Week number of the year as a decimal number, from first Sunday. // %OU Locale's alternative numeric rep. @@ -1359,182 +1720,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". @@ -1553,178 +1796,334 @@ 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]; + } + + // Fills __buf[0] and __buf[1] with "AM", "PM" depending on __h. + [[__gnu__::__always_inline__]] + static void + _S_fill_ampm(_CharT* __buf, chrono::hours __h) + { + auto __hi = __h.count(); + if (__hi >= 24) [[unlikely]] + __hi %= 24; + + constexpr const _CharT* __apm = _GLIBCXX_WIDEN("APM"); + __buf[0] = __apm[__hi >= 12]; + __buf[1] = __apm[2]; + } + + // Returns decimal representation of __n. + // Returned string_view may point to __buf. + [[__gnu__::__always_inline__]] + static basic_string_view<_CharT> + _S_str_d1(span<_CharT, 3> __buf, unsigned __n) + { + if (__n < 10) [[likely]] + return _S_digit(__n); + return _S_str_d2(__buf, __n); + } + + // Returns decimal representation of __n, padded to 2 digits. + // Returned string_view may point to __buf. + [[__gnu__::__always_inline__]] + static basic_string_view<_CharT> + _S_str_d2(span<_CharT, 3> __buf, unsigned __n) + { + if (__n < 100) [[likely]] + return _S_two_digits(__n); + return _S_str_d3(__buf, __n); + } - // Returns a hh_mm_ss. - template<typename _Tp> - static decltype(auto) - _S_hms(const _Tp& __t) + // 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_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; + default: + __builtin_unreachable(); } - } + return __res; + }; + + using __formatter_chrono<_CharT>::__formatter_chrono; + using __formatter_chrono<_CharT>::_M_spec; - // Returns a year_month_day. - template<typename _Tp> - static chrono::year_month_day - _S_date(const _Tp& __t) + 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); + // n.b. durations do not contain date parts, and for time point all + // date parts are computed, and they are always ok. + _M_spec._M_needs_ok_check = false; + + // 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) + // Return the formatting locale. + template<typename _FormatContext> + std::locale + _M_locale(_FormatContext& __fc) const { - using namespace chrono; - - if constexpr (is_same_v<_Tp, day>) - return __t; - else if constexpr (requires { __t.day(); }) - return __t.day(); + if (!_M_spec._M_localized) + return std::locale::classic(); else - return _S_date(__t).day(); + return __fc.locale(); } - template<typename _Tp> - static chrono::month - _S_month(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, month>) - return __t; - else if constexpr (requires { __t.month(); }) - return __t.month(); - else - return _S_date(__t).month(); + 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::year - _S_year(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, year>) - return __t; - else if constexpr (requires { __t.year(); }) - return __t.year(); - else - return _S_date(__t).year(); + const auto __prec = _M_spec._M_prec_kind != _WP_none + ? _M_spec._M_get_precision(__fc) + : _M_spec._M_prec; + + 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); + } + + using _Attoseconds = _ChronoData<_CharT>::_Attoseconds; + auto __nss = _S_subseconds(__ss); + __cd._M_subseconds = chrono::duration_cast<_Attoseconds>(__nss); + + auto __ssreps = __nss.count(); + auto __args_store + = std::make_format_args<_ErasedContext>(__ereps, __ssreps, __prec); + __cd._M_ereps = __args_store; + + return this->_M_format(__cd, __fc); } - template<typename _Tp> - static chrono::weekday - _S_weekday(const _Tp& __t) + // pre: __cd._M_lseconds and __cd._M_eseconds are set. + template<typename _Rep1, typename _Period1, typename _FormatContext> + typename _FormatContext::iterator + _M_format_time_point(_ChronoData<_CharT>& __cd, + const chrono::duration<_Rep1, _Period1>& __ed, + _FormatContext& __fc) const { - using namespace ::std::chrono; - using ::std::chrono::__detail::__local_time_fmt; - - if constexpr (is_same_v<_Tp, weekday>) - return __t; - else if constexpr (requires { __t.weekday(); }) - return __t.weekday(); - else if constexpr (is_same_v<_Tp, month_weekday>) - return __t.weekday_indexed().weekday(); - else if constexpr (is_same_v<_Tp, month_weekday_last>) - return __t.weekday_last().weekday(); - else - return weekday(_S_days(__t)); + auto __parts = _M_spec._M_needed - _ChronoParts::_TotalSeconds; + if ((__parts & _ChronoParts::_DateTime) != 0) + __cd._M_fill_date_time(__cd._M_lseconds, __parts); + return _M_format_units(__cd, __ed, __ed - __cd._M_eseconds, __fc); } + }; + +#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI + template<typename _CharT> + struct __formatter_chrono_info + { + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f._M_parse(__pc, _ChronoParts(), {}); } - // Remove subsecond precision from a time_point. - template<typename _Tp> - static auto - _S_floor_seconds(const _Tp& __t) + template<typename _Info, typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(const _Info& __i, + basic_format_context<_Out, _CharT>& __fc) const { - using chrono::__detail::__local_time_fmt; - if constexpr (chrono::__is_time_point_v<_Tp> - || chrono::__is_duration_v<_Tp>) - { - if constexpr (_Tp::period::den != 1) - return chrono::floor<chrono::seconds>(__t); - else - return __t; - } - else if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>) + // n.b. only acceptable chrono-spec for info is one containing + // only whitespaces and %%, that do not depend on formatted object. + if (!_M_f._M_spec._M_chrono_specs.empty()) [[unlikely]] + return _M_f._M_format(_ChronoData<_CharT>{}, __fc); + + const size_t __padwidth = _M_f._M_spec._M_get_width(__fc); + if (__padwidth == 0) + return _M_format_to(__fc.out(), __i); + + _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth); + _M_format_to(__sink.out(), __i); + return __sink._M_finish(_M_f._M_spec._M_align, _M_f._M_spec._M_fill); + } + + private: + template<typename _Out> + _Out + _M_format_to(_Out __out, const chrono::sys_info& __si) const + { + using _FmtStr = _Runtime_format_string<_CharT>; + // n.b. only decimal separator is locale dependent for specifiers + // used below, as sys_info uses seconds and minutes duration, the + // output is locale-independent. + constexpr auto* __fs + = _GLIBCXX_WIDEN("[{0:%F %T},{1:%F %T},{2:%T},{3:%Q%q},{0:%Z}]"); + const chrono::local_seconds __lb(__si.begin.time_since_epoch()); + return std::format_to(std::move(__out), _FmtStr(__fs), + chrono::local_time_format(__lb, &__si.abbrev), + __si.end, __si.offset, __si.save); + } + + template<typename _Out> + _Out + _M_format_to(_Out __out, const chrono::local_info& __li) const + { + *__out = _Separators<_CharT>::_S_squares()[0]; + ++__out; + if (__li.result == chrono::local_info::unique) + __out = _M_format_to(std::move(__out), __li.first); + else { - if constexpr (_Tp::fractional_width != 0) - return chrono::floor<chrono::seconds>(__t.to_duration()); + basic_string_view<_CharT> __sv; + if (__li.result == chrono::local_info::nonexistent) + __sv =_GLIBCXX_WIDEN("nonexistent"); else - return __t; + __sv = _GLIBCXX_WIDEN("ambiguous"); + __out = __format::__write(std::move(__out), __sv); + + __sv = _GLIBCXX_WIDEN(" local time between "); + __out = __format::__write(std::move(__out), __sv); + __out = _M_format_to(std::move(__out), __li.first); + + __sv = _GLIBCXX_WIDEN(" and "); + __out = __format::__write(std::move(__out), __sv); + __out = _M_format_to(std::move(__out), __li.second); } - else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>) - return _S_floor_seconds(__t._M_time); - else - return __t; + *__out = _Separators<_CharT>::_S_squares()[1]; + ++__out; + return std::move(__out); } - // Use the formatting locale's std::time_put facet to produce - // a locale-specific representation. - template<typename _Iter> - _Iter - _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm& __tm, - char __fmt, char __mod) const - { - basic_ostringstream<_CharT> __os; - __os.imbue(__loc); - const auto& __tp = use_facet<time_put<_CharT>>(__loc); - __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod); - if (__os) - __out = _M_write(std::move(__out), __loc, __os.view()); - return __out; - } + __formatter_chrono<_CharT> _M_f; }; +#endif } // namespace __format /// @endcond @@ -1736,12 +2135,8 @@ namespace __format constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) { - using namespace __format; - auto __it = _M_f._M_parse(__pc, _Duration|_TimeOfDay); - if constexpr (!is_floating_point_v<_Rep>) - if (_M_f._M_spec._M_prec_kind != __format::_WP_none) - __throw_format_error("format error: invalid precision for duration"); - return __it; + using enum __format::_ChronoParts; + return _M_f.template _M_parse<_Duration>(__pc, _EpochTime, __defSpec); } template<typename _Out> @@ -1759,16 +2154,54 @@ namespace __format using _URep = make_unsigned_t<_Rep>; auto __ucnt = -static_cast<_URep>(__d.count()); auto __ud = chrono::duration<_URep, _Period>(__ucnt); - return _M_f._M_format(__ud, __fc, true); + return _M_format(__ud, true, __fc); } else - return _M_f._M_format(-__d, __fc, true); + return _M_format(-__d, true, __fc); } - return _M_f._M_format(__d, __fc, false); + return _M_format(__d, false, __fc); } private: - __format::__formatter_chrono<_CharT> _M_f; + using _Duration = chrono::duration<_Rep, _Period>; + + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using enum __format::_ChronoParts; + auto __res = __format::__formatter_duration<_CharT>:: + template _S_spec_for<_Duration>(_None); + __res._M_localized = !is_integral_v<_Rep>; + // n.b. for integral format output is the same as ostream output + if constexpr (is_integral_v<_Rep>) + { + __res._M_needed = _EpochUnits|_UnitSuffix; + __res._M_chrono_specs = _GLIBCXX_WIDEN("%Q%q"); + } + return __res; + }(); + + template<typename _Rep2, typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + _M_format(const chrono::duration<_Rep2, _Period>& __d, + bool __is_neg, + basic_format_context<_Out, _CharT>& __fc) const + { + using namespace chrono; + using enum __format::_ChronoParts; + if constexpr (!is_integral_v<_Rep>) + if (_M_f._M_spec._M_chrono_specs.empty()) + return _M_f._M_format_to_ostream(__d, __is_neg, __fc); + + __format::_ChronoData<_CharT> __cd; + __cd._M_is_neg = __is_neg; + auto __ts = chrono::floor<chrono::seconds>(__d); + __cd._M_eseconds = __ts; + if (_M_f._M_spec._M_needs(_HoursMinutesSeconds)) + __cd._M_fill_time(__ts); + return _M_f._M_format_units(__cd, __d, __d - __ts, __fc); + } + + __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1776,16 +2209,35 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Day); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Day|_WeekdayIndex, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::day& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_fill_day(__t, __defSpec._M_needed); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_needed = _Day; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_d(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1793,16 +2245,37 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Month); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Month, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::month& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_month = __t; + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Month; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_m(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1810,16 +2283,35 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Year); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Year, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::year& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_year = __t; + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_needed = _Year; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_y(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1827,16 +2319,37 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Weekday); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Weekday, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::weekday& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_weekday = __t; + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Weekday; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_w(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1844,16 +2357,37 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Weekday); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _IndexedWeekday, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::weekday_indexed& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_fill_weekday(__t, __defSpec._M_needed); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _IndexedWeekday; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_wi(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1861,16 +2395,37 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Weekday); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Weekday, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::weekday_last& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_weekday = __t.weekday(); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Weekday; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_wl(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1878,16 +2433,38 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Month|_Day|_WeekdayIndex, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::month_day& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_month = __t.month(); + __cd._M_fill_day(__t.day(), __defSpec._M_needed); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Month|_Day; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_md(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1895,16 +2472,37 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Month, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::month_day_last& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_month = __t.month(); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Month; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ml(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1912,16 +2510,38 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Month|_IndexedWeekday, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::month_weekday& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_month = __t.month(); + __cd._M_fill_weekday(__t.weekday_indexed(), __defSpec._M_needed); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Month|_IndexedWeekday; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_mwi(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1929,16 +2549,38 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Month|_Weekday, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::month_weekday_last& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_month = __t.month(); + __cd._M_weekday = __t.weekday_last().weekday(); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Month|_Weekday; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_mwl(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1946,16 +2588,37 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Year|__format::_Month); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Year|_Month, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::year_month& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_fill_year_month(__t, __defSpec._M_needed); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Year|_Month; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ym(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1963,16 +2626,42 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Date); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Date, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::year_month_day& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + auto __parts = _M_f._M_spec._M_needed; + __parts = __cd._M_fill_year_month(__t, __parts); + __parts = __cd._M_fill_day(__t.day(), __parts); + if (__parts == 0) + return _M_f._M_format(__cd, __fc); + + chrono::local_days __ld(__t); + __cd._M_fill_ldays(__ld, __parts); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_needed = _YearMonthDay; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_f(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1980,16 +2669,48 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Date); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Date, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::year_month_day_last& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + auto __parts = _M_f._M_spec._M_needed; + __parts = __cd._M_fill_year_month(__t, __parts); + if (__parts == 0) + return _M_f._M_format(__cd, __fc); + + chrono::local_days __ld(__t); + __parts = __cd._M_fill_ldays(__ld, __parts); + if (__parts == 0) + return _M_f._M_format(__cd, __fc); + + chrono::year_month_day __ymd(__ld); + __cd._M_fill_day(__ymd.day(), __parts); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Year|_Month; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_yml(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -1997,16 +2718,50 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Date); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Date, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::year_month_weekday& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + auto __parts = _M_f._M_spec._M_needed; + __parts = __cd._M_fill_year_month(__t, __parts); + __parts = __cd._M_fill_weekday(__t.weekday_indexed(), __parts); + if (__parts == 0) + return _M_f._M_format(__cd, __fc); + + chrono::local_days __ld(__t); + __parts = __cd._M_fill_ldays(__ld, __parts); + if (__parts == 0) + return _M_f._M_format(__cd, __fc); + + chrono::year_month_day __ymd(__ld); + // n.b. weekday index is supplied by input, do not override it + __cd._M_day = __ymd.day(); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Year|_Month|_IndexedWeekday; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ymwi(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> @@ -2014,16 +2769,50 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_Date); } + { + using enum __format::_ChronoParts; + return _M_f._M_parse(__pc, _Date, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::year_month_weekday_last& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + auto __parts = _M_f._M_spec._M_needed; + __parts = __cd._M_fill_year_month(__t, __parts); + __cd._M_weekday = __t.weekday_last().weekday(); + __parts -= __format::_ChronoParts::_Weekday; + if (__parts == 0) + return _M_f._M_format(__cd, __fc); + + chrono::local_days __ld(__t); + __parts = __cd._M_fill_ldays(__ld, __parts); + if (__parts == 0) + return _M_f._M_format(__cd, __fc); + + chrono::year_month_day __ymd(__ld); + __cd._M_fill_day(__ymd.day(), __parts); + return _M_f._M_format(__cd, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using __format::_ChronoFormats; + using enum __format::_ChronoParts; + + __format::_ChronoSpec<_CharT> __res{}; + __res._M_debug = true; + __res._M_localized = true; + __res._M_locale_specific = true; + __res._M_needed = _Year|_Month|_Weekday; + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ymwl(); + return __res; + }(); + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<typename _Rep, typename _Period, __format::__char _CharT> @@ -2031,16 +2820,43 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_TimeOfDay); } + { + using enum __format::_ChronoParts; + return _M_f.template _M_parse<_Precision>(__pc, _Time, __defSpec); + } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + using enum __format::_ChronoParts; + + __format::_ChronoData<_CharT> __cd; + __cd._M_is_neg = __t.is_negative(); + __cd._M_hours = __t.hours(); + __cd._M_minutes = __t.minutes(); + __cd._M_seconds = __t.seconds(); + + _Precision __d(0); + // n.b. computing total duration or total seconds may overflow, + // do not compute them if not requested. + if (_M_f._M_spec._M_needs(_EpochUnits)) + __d = __t.to_duration(); + if (_M_f._M_spec._M_needs(_TotalSeconds)) + __cd._M_eseconds + = __cd._M_hours + __cd._M_minutes + __cd._M_seconds; + return _M_f._M_format_units(__cd, __d, __t.subseconds(), __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + using _Precision + = typename chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>::precision; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = + __format::__formatter_duration<_CharT>:: + template _S_spec_for<_Precision>(__format::_ChronoParts::_Time); + + __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI @@ -2049,16 +2865,16 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_ChronoParts{}); } + { return _M_f.parse(__pc); } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::sys_info& __i, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__i, __fc); } + { return _M_f.format(__i, __fc); } private: - __format::__formatter_chrono<_CharT> _M_f; + __format::__formatter_chrono_info<_CharT> _M_f; }; template<__format::__char _CharT> @@ -2066,16 +2882,16 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_ChronoParts{}); } + { return _M_f.parse(__pc); } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const chrono::local_info& __i, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__i, __fc); } + { return _M_f.format(__i, __fc); } private: - __format::__formatter_chrono<_CharT> _M_f; + __format::__formatter_chrono_info<_CharT> _M_f; }; #endif @@ -2085,7 +2901,9 @@ namespace __format constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) { - auto __next = _M_f._M_parse(__pc, __format::_ZonedDateTime); + using enum __format::_ChronoParts; + auto __next + = _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec); if constexpr (!__stream_insertable) if (_M_f._M_spec._M_chrono_specs.empty()) __format::__invalid_chrono_spec(); // chrono-specs can't be empty @@ -2096,14 +2914,34 @@ namespace __format typename basic_format_context<_Out, _CharT>::iterator format(const chrono::sys_time<_Duration>& __t, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + __cd._M_fill_utc_zone(); + + _Duration __ed = __t.time_since_epoch(); + __cd._M_eseconds = chrono::floor<chrono::seconds>(__ed); + __cd._M_lseconds = chrono::local_seconds(__cd._M_eseconds); + return _M_f._M_format_time_point(__cd, __ed, __fc); + } private: static constexpr bool __stream_insertable = requires (basic_ostream<_CharT>& __os, chrono::sys_time<_Duration> __t) { __os << __t; }; - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using enum __format::_ChronoParts; + __format::_ChronoParts __needed = _DateTime; + if constexpr (!__stream_insertable) + __needed = _None; + else if constexpr (is_convertible_v<_Duration, chrono::days>) + __needed = _Date; + return __format::__formatter_duration<_CharT>:: + template _S_spec_for<_Duration>(__needed); + }(); + + __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; template<typename _Duration, __format::__char _CharT> @@ -2112,32 +2950,43 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_ZonedDateTime); } + { + using enum __format::_ChronoParts; + return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec); + } template<typename _Out> - typename basic_format_context<_Out, _CharT>::iterator - format(const chrono::utc_time<_Duration>& __t, + typename basic_format_context<_Out, _CharT>::iterator + format(const chrono::utc_time<_Duration>& __t, basic_format_context<_Out, _CharT>& __fc) const { + using __format::_ChronoParts; + using namespace chrono; + __format::_ChronoData<_CharT> __cd{}; + __cd._M_fill_utc_zone(); + + _Duration __ed = __t.time_since_epoch(); + __cd._M_eseconds = chrono::floor<seconds>(__ed); // Adjust by removing leap seconds to get equivalent sys_time. // We can't just use clock_cast because we want to know if the time // falls within a leap second insertion, and format seconds as "60". - using chrono::__detail::__utc_leap_second; - using chrono::seconds; - using chrono::sys_time; - using _CDur = common_type_t<_Duration, seconds>; const auto __li = chrono::get_leap_second_info(__t); - sys_time<_CDur> __s{__t.time_since_epoch() - __li.elapsed}; - if (!__li.is_leap_second) [[likely]] - return _M_f._M_format(__s, __fc); - else - return _M_f._M_format(__utc_leap_second(__s), __fc); + __cd._M_lseconds = local_seconds(__cd._M_eseconds - __li.elapsed); + auto __parts = _M_f._M_spec._M_needed - _ChronoParts::_TotalSeconds; + if ((__parts & _ChronoParts::_DateTime) != 0) + { + __cd._M_fill_date_time(__cd._M_lseconds, __parts); + __cd._M_seconds += seconds(__li.is_leap_second); + } + return _M_f._M_format_units(__cd, __ed, __ed - __cd._M_eseconds, __fc); } private: - friend formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT>; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = + __format::__formatter_duration<_CharT>:: + template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime); - __format::__formatter_chrono<_CharT> _M_f; + __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; template<typename _Duration, __format::__char _CharT> @@ -2146,29 +2995,34 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_ZonedDateTime); } + { + using enum __format::_ChronoParts; + return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec); + } template<typename _Out> - typename basic_format_context<_Out, _CharT>::iterator - format(const chrono::tai_time<_Duration>& __t, + typename basic_format_context<_Out, _CharT>::iterator + format(const chrono::tai_time<_Duration>& __t, basic_format_context<_Out, _CharT>& __fc) const { - // Convert to __local_time_fmt with abbrev "TAI" and offset 0s. - // We use __local_time_fmt and not sys_time (as the standard implies) - // because %Z for sys_time would print "UTC" and we want "TAI" here. + using namespace chrono; + __format::_ChronoData<_CharT> __cd{}; + __cd._M_fill_zone("TAI", L"TAI"); + _Duration __ed = __t.time_since_epoch(); + __cd._M_eseconds = chrono::floor<seconds>(__ed); // Offset is 1970y/January/1 - 1958y/January/1 constexpr chrono::days __tai_offset = chrono::days(4383); - using _CDur = common_type_t<_Duration, chrono::days>; - chrono::local_time<_CDur> __lt(__t.time_since_epoch() - __tai_offset); - const string __abbrev("TAI", 3); - const chrono::seconds __off = 0s; - const auto __lf = chrono::local_time_format(__lt, &__abbrev, &__off); - return _M_f._M_format(__lf, __fc); + __cd._M_lseconds = local_seconds(__cd._M_eseconds - __tai_offset); + return _M_f._M_format_time_point(__cd, __ed, __fc); } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = + __format::__formatter_duration<_CharT>:: + template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime); + + __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; template<typename _Duration, __format::__char _CharT> @@ -2177,29 +3031,34 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_ZonedDateTime); } + { + using enum __format::_ChronoParts; + return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec); + } template<typename _Out> - typename basic_format_context<_Out, _CharT>::iterator - format(const chrono::gps_time<_Duration>& __t, + typename basic_format_context<_Out, _CharT>::iterator + format(const chrono::gps_time<_Duration>& __t, basic_format_context<_Out, _CharT>& __fc) const { - // Convert to __local_time_fmt with abbrev "GPS" and offset 0s. - // We use __local_time_fmt and not sys_time (as the standard implies) - // because %Z for sys_time would print "UTC" and we want "GPS" here. + using namespace chrono; + __format::_ChronoData<_CharT> __cd{}; + __cd._M_fill_zone("GPS", L"GPS"); + _Duration __ed = __t.time_since_epoch(); + __cd._M_eseconds = chrono::floor<seconds>(__ed); // Offset is 1980y/January/Sunday[1] - 1970y/January/1 constexpr chrono::days __gps_offset = chrono::days(3657); - using _CDur = common_type_t<_Duration, chrono::days>; - chrono::local_time<_CDur> __lt(__t.time_since_epoch() + __gps_offset); - const string __abbrev("GPS", 3); - const chrono::seconds __off = 0s; - const auto __lf = chrono::local_time_format(__lt, &__abbrev, &__off); - return _M_f._M_format(__lf, __fc); + __cd._M_lseconds = local_seconds(__cd._M_eseconds + __gps_offset); + return _M_f._M_format_time_point(__cd, __ed, __fc); } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = + __format::__formatter_duration<_CharT>:: + template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime); + + __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; template<typename _Duration, __format::__char _CharT> @@ -2207,36 +3066,70 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_ZonedDateTime); } + { + using enum __format::_ChronoParts; + return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec); + } template<typename _Out> - typename basic_format_context<_Out, _CharT>::iterator - format(const chrono::file_time<_Duration>& __t, + typename basic_format_context<_Out, _CharT>::iterator + format(const chrono::file_time<_Duration>& __t, basic_format_context<_Out, _CharT>& __fc) const { using namespace chrono; - return _M_f._M_format(chrono::clock_cast<system_clock>(__t), __fc); + __format::_ChronoData<_CharT> __cd{}; + __cd._M_fill_utc_zone(); + + _Duration __ed = __t.time_since_epoch(); + __cd._M_eseconds = chrono::floor<seconds>(__ed); + auto __st = chrono::clock_cast<system_clock>(__t); + __cd._M_lseconds + = local_seconds(chrono::floor<seconds>(__st.time_since_epoch())); + return _M_f._M_format_time_point(__cd, __ed, __fc); } private: - __format::__formatter_chrono<_CharT> _M_f; - }; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = + __format::__formatter_duration<_CharT>:: + template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime); + + __format::__formatter_duration<_CharT> _M_f{__defSpec}; + }; template<typename _Duration, __format::__char _CharT> struct formatter<chrono::local_time<_Duration>, _CharT> { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_DateTime); } + { + using enum __format::_ChronoParts; + return _M_f.template _M_parse<_Duration>(__pc, _DateTime, __defSpec); + } template<typename _Out> - typename basic_format_context<_Out, _CharT>::iterator - format(const chrono::local_time<_Duration>& __t, + typename basic_format_context<_Out, _CharT>::iterator + format(const chrono::local_time<_Duration>& __lt, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc); } + { + __format::_ChronoData<_CharT> __cd{}; + _Duration __ed = __lt.time_since_epoch(); + __cd._M_lseconds = chrono::floor<chrono::seconds>(__lt); + __cd._M_eseconds = __cd._M_lseconds.time_since_epoch(); + return _M_f._M_format_time_point(__cd, __ed, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + using enum __format::_ChronoParts; + __format::_ChronoParts __needed = _DateTime; + if constexpr (is_convertible_v<_Duration, chrono::days>) + __needed = _Date; + return __format::__formatter_duration<_CharT>:: + template _S_spec_for<_Duration>(__needed); + }(); + + __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; template<typename _Duration, __format::__char _CharT> @@ -2244,16 +3137,59 @@ namespace __format { constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { return _M_f._M_parse(__pc, __format::_ZonedDateTime); } + { + using enum __format::_ChronoParts; + return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec); + } template<typename _Out> - typename basic_format_context<_Out, _CharT>::iterator - format(const chrono::__detail::__local_time_fmt<_Duration>& __t, + typename basic_format_context<_Out, _CharT>::iterator + format(const chrono::__detail::__local_time_fmt<_Duration>& __zt, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f._M_format(__t, __fc, /* use %Z for {} */ true); } + { + using enum __format::_ChronoParts; + __format::_ChronoData<_CharT> __cd{}; + + if (_M_f._M_spec._M_needs(_ZoneOffset)) + { + if (!__zt._M_offset_sec) + std::__throw_format_error("format error: no timezone available for %z"); + __cd._M_zone_offset = *__zt._M_offset_sec; + } + + basic_string<_CharT> __zone_store; + if (_M_f._M_spec._M_needs(_ZoneAbbrev)) + { + if (!__zt._M_abbrev) + std::__throw_format_error("format error: no timezone available for %Z"); + + __cd._M_zone_cstr = __zt._M_abbrev->data(); + if constexpr (is_same_v<_CharT, char>) + __cd._M_zone_abbrev = *__zt._M_abbrev; + else + { + // TODO: use resize_for_override + __zone_store.resize(__zt._M_abbrev->size()); + auto& __ct = use_facet<ctype<_CharT>>(_M_f._M_locale(__fc)); + __ct.widen(__zt._M_abbrev->data(), + __zt._M_abbrev->data() + __zt._M_abbrev->size(), + __zone_store.data()); + __cd._M_zone_abbrev = __zone_store; + } + } + + _Duration __ed = __zt._M_time.time_since_epoch(); + __cd._M_lseconds = chrono::floor<chrono::seconds>(__zt._M_time); + __cd._M_eseconds = __cd._M_lseconds.time_since_epoch(); + return _M_f._M_format_time_point(__cd, __ed, __fc); + } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = + __format::__formatter_duration<_CharT>:: + template _S_spec_for<_Duration>(__format::_ChronoParts::_ZonedDateTime); + + __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI @@ -2262,8 +3198,8 @@ namespace __format : formatter<chrono::__detail::__local_time_fmt_for<_Duration>, _CharT> { template<typename _Out> - typename basic_format_context<_Out, _CharT>::iterator - format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp, + typename basic_format_context<_Out, _CharT>::iterator + format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp, basic_format_context<_Out, _CharT>& __fc) const { using _Ltf = chrono::__detail::__local_time_fmt_for<_Duration>; @@ -2277,18 +3213,6 @@ namespace __format }; #endif - // Partial specialization needed for %c formatting of __utc_leap_second. - template<typename _Duration, __format::__char _CharT> - struct formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT> - : formatter<chrono::utc_time<_Duration>, _CharT> - { - template<typename _Out> - typename basic_format_context<_Out, _CharT>::iterator - format(const chrono::__detail::__utc_leap_second<_Duration>& __t, - basic_format_context<_Out, _CharT>& __fc) const - { return this->_M_f._M_format(__t, __fc); } - }; - namespace chrono { /// @addtogroup chrono @@ -2869,10 +3793,7 @@ namespace __detail basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __i) { - __os << '[' << __i.begin << ',' << __i.end - << ',' << hh_mm_ss(__i.offset) << ',' << __i.save - << ',' << __i.abbrev << ']'; - return __os; + return __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{}"), __i); } /// Writes a local_info object to an ostream in an unspecified format. @@ -2880,19 +3801,19 @@ namespace __detail basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __li) { - __os << '['; + __os << __format::_Separators<_CharT>::_S_squares()[0]; if (__li.result == local_info::unique) __os << __li.first; else { if (__li.result == local_info::nonexistent) - __os << "nonexistent"; + __os << _GLIBCXX_WIDEN("nonexistent"); else - __os << "ambiguous"; - __os << " local time between " << __li.first; - __os << " and " << __li.second; + __os << _GLIBCXX_WIDEN("ambiguous"); + __os << _GLIBCXX_WIDEN(" local time between ") << __li.first; + __os << _GLIBCXX_WIDEN(" and ") << __li.second; } - __os << ']'; + __os << __format::_Separators<_CharT>::_S_squares()[1]; return __os; } @@ -3049,8 +3970,7 @@ namespace __detail if (!__offset) __offset = &__off; using __format::_ChronoParts; - auto __need = _ChronoParts::_Year | _ChronoParts::_Month - | _ChronoParts::_Day | _ChronoParts::_TimeOfDay; + auto __need = _ChronoParts::_YearMonthDay | _ChronoParts::_TimeOfDay; __detail::_Parser_t<_Duration> __p(__need); if (__p(__is, __fmt, __abbrev, __offset)) { @@ -3108,8 +4028,7 @@ namespace __detail minutes* __offset = nullptr) { using __format::_ChronoParts; - auto __need = _ChronoParts::_Year | _ChronoParts::_Month - | _ChronoParts::_Day | _ChronoParts::_TimeOfDay; + auto __need = _ChronoParts::_YearMonthDay | _ChronoParts::_TimeOfDay; __detail::_Parser_t<_Duration> __p(__need); if (__p(__is, __fmt, __abbrev, __offset)) { @@ -3362,8 +4281,8 @@ namespace __detail minutes __tz_offset = __bad_min; basic_string<_CharT, _Traits> __tz_abbr; - if ((_M_need & _ChronoParts::_TimeOfDay) - && (_M_need & _ChronoParts::_Year)) + if ((_M_need & _ChronoParts::_TimeOfDay) != 0 + && (_M_need & _ChronoParts::_Year) != 0) { // For time_points assume "00:00:00" is implicitly present, // so we don't fail to parse if it's not (PR libstdc++/114240). @@ -3636,7 +4555,7 @@ namespace __detail } else { - if (_M_need & _ChronoParts::_TimeOfDay) + if ((_M_need & _ChronoParts::_TimeOfDay) != 0) __err |= ios_base::failbit; break; } @@ -3704,7 +4623,7 @@ namespace __detail __min = minutes(__val); else { - if (_M_need & _ChronoParts::_TimeOfDay) + if ((_M_need & _ChronoParts::_TimeOfDay) != 0) __err |= ios_base::failbit; break; } @@ -3794,7 +4713,7 @@ namespace __detail auto __val = __read_unsigned(2); if (__val == -1 || __val > 23) [[unlikely]] { - if (_M_need & _ChronoParts::_TimeOfDay) + if ((_M_need & _ChronoParts::_TimeOfDay) != 0) __err |= ios_base::failbit; break; } @@ -3805,7 +4724,7 @@ namespace __detail __val = __read_unsigned(2); if (__val == -1 || __val > 60) [[unlikely]] { - if (_M_need & _ChronoParts::_TimeOfDay) + if ((_M_need & _ChronoParts::_TimeOfDay) != 0) __err |= ios_base::failbit; break; } @@ -3840,7 +4759,7 @@ namespace __detail __s = seconds(__val); else { - if (_M_need & _ChronoParts::_TimeOfDay) + if ((_M_need & _ChronoParts::_TimeOfDay) != 0) __err |= ios_base::failbit; break; } @@ -4314,23 +5233,23 @@ namespace __detail // Whether the caller wants _M_wd. // The _Weekday bit is only set for chrono::weekday. - const bool __need_wday = _M_need & _ChronoParts::_Weekday; + const bool __need_wday = (_M_need & _ChronoParts::_Weekday) != 0; // Whether the caller wants _M_sys_days and _M_time. // Only true for durations and time_points. - const bool __need_time = _M_need & _ChronoParts::_TimeOfDay; + const bool __need_time = (_M_need & _ChronoParts::_TimeOfDay) != 0; if (__need_wday && __wday != __bad_wday) _M_wd = __wday; // Caller only wants a weekday and we have one. - else if (_M_need & _ChronoParts::_Date) // subsumes __need_wday + else if ((_M_need & _ChronoParts::_Date) != 0) // subsumes __need_wday { // Whether the caller wants _M_ymd. // True for chrono::year etc., false for time_points. const bool __need_ymd = !__need_wday && !__need_time; - if ((_M_need & _ChronoParts::_Year && __y == __bad_y) - || (_M_need & _ChronoParts::_Month && __m == __bad_mon) - || (_M_need & _ChronoParts::_Day && __d == __bad_day)) + if (((_M_need & _ChronoParts::_Year) != 0 && __y == __bad_y) + || ((_M_need & _ChronoParts::_Month) != 0 && __m == __bad_mon) + || ((_M_need & _ChronoParts::_Day) != 0 && __d == __bad_day)) { // Missing at least one of y/m/d so calculate sys_days // from the other data we have available. @@ -4407,7 +5326,7 @@ namespace __detail // but check that their values are in range. // Make unwanted fields valid so that _M_ymd.ok() is true. - if (_M_need & _ChronoParts::_Year) + if ((_M_need & _ChronoParts::_Year) != 0) { if (!__y.ok()) [[unlikely]] __err |= ios_base::failbit; @@ -4415,7 +5334,7 @@ namespace __detail else if (__y == __bad_y) __y = 1972y; // Leap year so that Feb 29 is valid. - if (_M_need & _ChronoParts::_Month) + if ((_M_need & _ChronoParts::_Month) != 0) { if (!__m.ok()) [[unlikely]] __err |= ios_base::failbit; @@ -4423,7 +5342,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/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h index b1a6206..38cea4c 100644 --- a/libstdc++-v3/include/bits/cpp_type_traits.h +++ b/libstdc++-v3/include/bits/cpp_type_traits.h @@ -273,6 +273,12 @@ __INT_N(__GLIBCXX_TYPE_INT_N_2) __INT_N(__GLIBCXX_TYPE_INT_N_3) #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 treat signed/unsigned __int128 as integral types. +__INT_N(__int128) +#endif + #undef __INT_N // @@ -307,6 +313,15 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3) typedef __true_type __type; }; +#ifdef _GLIBCXX_USE_FLOAT128 + template<> + struct __is_floating<__float128> + { + enum { __value = 1 }; + typedef __true_type __type; + }; +#endif + #ifdef __STDCPP_FLOAT16_T__ template<> struct __is_floating<_Float16> @@ -545,17 +560,6 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3) { enum { __width = __GLIBCXX_BITSIZE_INT_N_3 }; }; #endif -#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ - // In strict modes __is_integer<__int128> is false, - // but we want to allow memcpy between signed/unsigned __int128. - __extension__ - template<> - struct __memcpyable_integer<__int128> { enum { __width = 128 }; }; - __extension__ - template<> - struct __memcpyable_integer<unsigned __int128> { enum { __width = 128 }; }; -#endif - #if _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 && _GLIBCXX_LDOUBLE_IS_IEEE_BINARY64 template<> struct __memcpyable<double*, long double*> { enum { __value = true }; }; 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 a6b5ac8..314b55d 100644 --- a/libstdc++-v3/include/bits/formatfwd.h +++ b/libstdc++-v3/include/bits/formatfwd.h @@ -37,6 +37,12 @@ // <bits/version.h> must have been included before this header: #ifdef __glibcxx_format // C++ >= 20 && HOSTED +#include <concepts> +#include <type_traits> +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED +# include <bits/ranges_base.h> // input_range, range_reference_t +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -50,6 +56,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // [format.formatter], formatter template<typename _Tp, typename _CharT = char> struct formatter; +/// @cond undocumented + [[noreturn]] + inline void + __throw_format_error(const char* __what); + namespace __format { #ifdef _GLIBCXX_USE_WCHAR_T @@ -60,10 +71,125 @@ namespace __format concept __char = same_as<_CharT, char>; #endif - template<__char _CharT> - struct __formatter_int; + enum class _Align : unsigned char { + _Align_default, + _Align_left, + _Align_right, + _Align_centre, + }; + using enum _Align; + + template<typename _CharT> struct _Spec; + + template<__char _CharT> struct __formatter_str; + template<__char _CharT> struct __formatter_int; + template<__char _CharT> struct __formatter_ptr; + + template<typename _Tp, typename _Context, + typename _Formatter + = typename _Context::template formatter_type<remove_const_t<_Tp>>, + typename _ParseContext + = basic_format_parse_context<typename _Context::char_type>> + concept __parsable_with + = semiregular<_Formatter> + && requires (_Formatter __f, _ParseContext __pc) + { + { __f.parse(__pc) } -> same_as<typename _ParseContext::iterator>; + }; + + template<typename _Tp, typename _Context, + typename _Formatter + = typename _Context::template formatter_type<remove_const_t<_Tp>>, + typename _ParseContext + = basic_format_parse_context<typename _Context::char_type>> + concept __formattable_with + = semiregular<_Formatter> + && requires (const _Formatter __cf, _Tp&& __t, _Context __fc) + { + { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>; + }; + + // An unspecified output iterator type used in the `formattable` concept. + template<typename _CharT> + struct _Iter_for; + template<typename _CharT> + using _Iter_for_t = typename _Iter_for<_CharT>::type; + + template<typename _Tp, typename _CharT, + typename _Context = basic_format_context<_Iter_for_t<_CharT>, _CharT>> + concept __formattable_impl + = __parsable_with<_Tp, _Context> && __formattable_with<_Tp, _Context>; + + template<typename _Formatter> + concept __has_debug_format = requires(_Formatter __f) + { + __f.set_debug_format(); + }; +} // namespace __format +/// @endcond + +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED + // [format.formattable], concept formattable + template<typename _Tp, typename _CharT> + concept formattable + = __format::__formattable_impl<remove_reference_t<_Tp>, _CharT>; + + template<typename _Tp, __format::__char _CharT = char> + requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT> + class range_formatter; + +/// @cond undocumented +namespace __format +{ + template<typename _Rg, typename _CharT> + concept __const_formattable_range + = ranges::input_range<const _Rg> + && formattable<ranges::range_reference_t<const _Rg>, _CharT>; + + // _Rg& and const _Rg& are both formattable and use same formatter + // specialization for their references. + template<typename _Rg, typename _CharT> + concept __simply_formattable_range + = __const_formattable_range<_Rg, _CharT> + && same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, + remove_cvref_t<ranges::range_reference_t<const _Rg>>>; + + template<typename _Rg, typename _CharT> + using __maybe_const_range + = __conditional_t<__const_formattable_range<_Rg, _CharT>, const _Rg, _Rg>; + + template<typename _Tp, typename _CharT> + using __maybe_const + = __conditional_t<formattable<const _Tp, _CharT>, const _Tp, _Tp>; } + // [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 } // namespace std #endif // __glibcxx_format 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/functional_hash.h b/libstdc++-v3/include/bits/functional_hash.h index e84c9ee..8456089 100644 --- a/libstdc++-v3/include/bits/functional_hash.h +++ b/libstdc++-v3/include/bits/functional_hash.h @@ -199,6 +199,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Cxx_hashtable_define_trivial_hash(__GLIBCXX_TYPE_INT_N_3 unsigned) #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 treat signed/unsigned __int128 as integral types. + __extension__ + _Cxx_hashtable_define_trivial_hash(__int128) + __extension__ + _Cxx_hashtable_define_trivial_hash(__int128 unsigned) +#endif + #undef _Cxx_hashtable_define_trivial_hash struct _Hash_impl diff --git a/libstdc++-v3/include/bits/funcwrap.h b/libstdc++-v3/include/bits/funcwrap.h new file mode 100644 index 0000000..70ecfd9 --- /dev/null +++ b/libstdc++-v3/include/bits/funcwrap.h @@ -0,0 +1,615 @@ +// 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; + } + + void _M_destroy() noexcept + { _M_manage(_Manager::_Op::_Destroy, _M_storage, nullptr); } + + ~_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); + } + + _Manager::_Func _M_manage; + _Storage _M_storage; + }; +#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..89fa8c8 --- /dev/null +++ b/libstdc++-v3/include/bits/indirect.h @@ -0,0 +1,836 @@ +// 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 + { + // n.b. [allocator.requirements.general] p22 implies + // dereferencing const pointer is same as pointer + const indirect& __iself = (const indirect&)__self; + __glibcxx_assert(__iself._M_objp != nullptr); + return std::forward_like<_Self>(*__iself._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..fd91b22 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -148,7 +148,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; template<typename _Tp> - static constexpr bool + static consteval bool _S_noexcept() { if constexpr (__adl_imove<_Tp>) @@ -214,17 +214,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = make_signed_t<decltype(std::declval<_Tp>() - std::declval<_Tp>())>; }; -#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ - // __int128 is incrementable even if !integral<__int128> - template<> - struct incrementable_traits<__int128> - { using difference_type = __int128; }; - - template<> - struct incrementable_traits<unsigned __int128> - { using difference_type = __int128; }; -#endif - namespace __detail { // An iterator such that iterator_traits<_Iter> names a specialization @@ -611,24 +600,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION class __max_diff_type; class __max_size_type; - __extension__ - template<typename _Tp> - concept __is_signed_int128 -#if __SIZEOF_INT128__ - = same_as<_Tp, __int128>; -#else - = false; -#endif - - __extension__ - template<typename _Tp> - concept __is_unsigned_int128 -#if __SIZEOF_INT128__ - = same_as<_Tp, unsigned __int128>; -#else - = false; -#endif - template<typename _Tp> concept __cv_bool = same_as<const volatile _Tp, const volatile bool>; @@ -636,16 +607,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION concept __integral_nonbool = integral<_Tp> && !__cv_bool<_Tp>; template<typename _Tp> - concept __is_int128 = __is_signed_int128<_Tp> || __is_unsigned_int128<_Tp>; - - template<typename _Tp> concept __is_integer_like = __integral_nonbool<_Tp> - || __is_int128<_Tp> || same_as<_Tp, __max_diff_type> || same_as<_Tp, __max_size_type>; template<typename _Tp> concept __is_signed_integer_like = signed_integral<_Tp> - || __is_signed_int128<_Tp> || same_as<_Tp, __max_diff_type>; } // namespace ranges::__detail @@ -918,7 +884,7 @@ namespace ranges { private: template<typename _Tp, typename _Up> - static constexpr bool + static consteval bool _S_noexcept() { if constexpr (__adl_iswap<_Tp, _Up>) @@ -1022,19 +988,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 +1001,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/locale_conv.h b/libstdc++-v3/include/bits/locale_conv.h index 076e14f..b08795d 100644 --- a/libstdc++-v3/include/bits/locale_conv.h +++ b/libstdc++-v3/include/bits/locale_conv.h @@ -85,16 +85,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return false; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr // The codecvt facet will only return noconv when the types are // the same, so avoid instantiating basic_string::assign otherwise - if _GLIBCXX17_CONSTEXPR (is_same<typename _Codecvt::intern_type, - typename _Codecvt::extern_type>()) + if constexpr (is_same<typename _Codecvt::intern_type, + typename _Codecvt::extern_type>::value) if (__result == codecvt_base::noconv) { __outstr.assign(__first, __last); __count = __last - __first; return true; } +#pragma GCC diagnostic pop __outstr.resize(__outchars); __count = __next - __first; diff --git a/libstdc++-v3/include/bits/max_size_type.h b/libstdc++-v3/include/bits/max_size_type.h index 5bec0b5..a34b91a 100644 --- a/libstdc++-v3/include/bits/max_size_type.h +++ b/libstdc++-v3/include/bits/max_size_type.h @@ -36,7 +36,9 @@ #if __cplusplus > 201703L && __cpp_lib_concepts #include <ext/numeric_traits.h> +#include <bit> // __bit_width #include <numbers> +#include <limits> // __glibcxx_integral_traps // This header implements unsigned and signed integer-class types (as per // [iterator.concept.winc]) that are one bit wider than the widest supported @@ -63,7 +65,7 @@ namespace ranges public: __max_size_type() = default; - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> constexpr __max_size_type(_Tp __i) noexcept : _M_val(__i), _M_msb(__i < 0) @@ -72,7 +74,7 @@ namespace ranges constexpr explicit __max_size_type(const __max_diff_type& __d) noexcept; - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> constexpr explicit operator _Tp() const noexcept { return _M_val; } @@ -258,52 +260,52 @@ namespace ranges return *this; } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator+=(_Tp& __a, const __max_size_type& __b) noexcept { return (__a = static_cast<_Tp>(__a + __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator-=(_Tp& __a, const __max_size_type& __b) noexcept { return (__a = static_cast<_Tp>(__a - __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator*=(_Tp& __a, const __max_size_type& __b) noexcept { return (__a = static_cast<_Tp>(__a * __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator/=(_Tp& __a, const __max_size_type& __b) noexcept { return (__a = static_cast<_Tp>(__a / __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator%=(_Tp& __a, const __max_size_type& __b) noexcept { return (__a = static_cast<_Tp>(__a % __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator&=(_Tp& __a, const __max_size_type& __b) noexcept { return (__a = static_cast<_Tp>(__a & __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator|=(_Tp& __a, const __max_size_type& __b) noexcept { return (__a = static_cast<_Tp>(__a | __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator^=(_Tp& __a, const __max_size_type& __b) noexcept { return (__a = static_cast<_Tp>(__a ^ __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator<<=(_Tp& __a, const __max_size_type& __b) noexcept { return (__a = static_cast<_Tp>(__a << __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator>>=(_Tp& __a, const __max_size_type& __b) noexcept { return (__a = static_cast<_Tp>(__a >> __b)); } @@ -425,10 +427,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) @@ -444,7 +447,7 @@ namespace ranges public: __max_diff_type() = default; - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> constexpr __max_diff_type(_Tp __i) noexcept : _M_rep(__i) @@ -455,7 +458,7 @@ namespace ranges : _M_rep(__d) { } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> constexpr explicit operator _Tp() const noexcept { return static_cast<_Tp>(_M_rep); } @@ -588,52 +591,52 @@ namespace ranges return *this; } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator+=(_Tp& __a, const __max_diff_type& __b) noexcept { return (__a = static_cast<_Tp>(__a + __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator-=(_Tp& __a, const __max_diff_type& __b) noexcept { return (__a = static_cast<_Tp>(__a - __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator*=(_Tp& __a, const __max_diff_type& __b) noexcept { return (__a = static_cast<_Tp>(__a * __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator/=(_Tp& __a, const __max_diff_type& __b) noexcept { return (__a = static_cast<_Tp>(__a / __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator%=(_Tp& __a, const __max_diff_type& __b) noexcept { return (__a = static_cast<_Tp>(__a % __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator&=(_Tp& __a, const __max_diff_type& __b) noexcept { return (__a = static_cast<_Tp>(__a & __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator|=(_Tp& __a, const __max_diff_type& __b) noexcept { return (__a = static_cast<_Tp>(__a | __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator^=(_Tp& __a, const __max_diff_type& __b) noexcept { return (__a = static_cast<_Tp>(__a ^ __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator<<=(_Tp& __a, const __max_diff_type& __b) noexcept { return (__a = static_cast<_Tp>(__a << __b)); } - template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp> + template<typename _Tp> requires integral<_Tp> friend constexpr _Tp& operator>>=(_Tp& __a, const __max_diff_type& __b) noexcept { return (__a = static_cast<_Tp>(__a >> __b)); } @@ -752,7 +755,6 @@ namespace ranges { return !(__l < __r); } #endif - private: __max_size_type _M_rep = 0; friend class __max_size_type; @@ -774,10 +776,27 @@ namespace ranges static constexpr bool is_signed = false; static constexpr bool is_integer = true; static constexpr bool is_exact = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr bool traps = __glibcxx_integral_traps; + static constexpr int radix = 2; static constexpr int digits = __gnu_cxx::__int_traits<_Sp::__rep>::__digits + 1; static constexpr int digits10 = static_cast<int>(digits * numbers::ln2 / numbers::ln10); + static constexpr int max_digits10 = 0; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool is_iec559 = false; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + static constexpr bool has_denorm_loss = false; + static constexpr bool tinyness_before = false; + static constexpr float_denorm_style has_denorm = denorm_absent; + static constexpr float_round_style round_style = round_toward_zero; static constexpr _Sp min() noexcept @@ -790,6 +809,30 @@ namespace ranges static constexpr _Sp lowest() noexcept { return min(); } + + static constexpr _Sp + denorm_min() noexcept + { return 0; } + + static constexpr _Sp + epsilon() noexcept + { return 0; } + + static constexpr _Sp + round_error() noexcept + { return 0; } + + static constexpr _Sp + infinity() noexcept + { return 0; } + + static constexpr _Sp + quiet_NaN() noexcept + { return 0; } + + static constexpr _Sp + signaling_NaN() noexcept + { return 0; } }; template<> @@ -801,9 +844,26 @@ namespace ranges static constexpr bool is_signed = true; static constexpr bool is_integer = true; static constexpr bool is_exact = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr bool traps = __glibcxx_integral_traps; + static constexpr int radix = 2; static constexpr int digits = numeric_limits<_Sp>::digits - 1; static constexpr int digits10 = static_cast<int>(digits * numbers::ln2 / numbers::ln10); + static constexpr int max_digits10 = 0; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool is_iec559 = false; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + static constexpr bool has_denorm_loss = false; + static constexpr bool tinyness_before = false; + static constexpr float_denorm_style has_denorm = denorm_absent; + static constexpr float_round_style round_style = round_toward_zero; static constexpr _Dp min() noexcept @@ -816,8 +876,42 @@ namespace ranges static constexpr _Dp lowest() noexcept { return min(); } + + static constexpr _Dp + denorm_min() noexcept + { return 0; } + + static constexpr _Dp + epsilon() noexcept + { return 0; } + + static constexpr _Dp + round_error() noexcept + { return 0; } + + static constexpr _Dp + infinity() noexcept + { return 0; } + + static constexpr _Dp + quiet_NaN() noexcept + { return 0; } + + static constexpr _Dp + signaling_NaN() noexcept + { return 0; } }; + 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.h b/libstdc++-v3/include/bits/move.h index e91b003..8c4f461 100644 --- a/libstdc++-v3/include/bits/move.h +++ b/libstdc++-v3/include/bits/move.h @@ -89,7 +89,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return static_cast<_Tp&&>(__t); } -#if __glibcxx_forward_like // C++ >= 23 template<typename _Tp, typename _Up> struct __like_impl; // _Tp must be a reference and _Up an lvalue reference @@ -112,6 +111,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Up> using __like_t = typename __like_impl<_Tp&&, _Up&>::type; +#if __glibcxx_forward_like // C++ >= 23 /** @brief Forward with the cv-qualifiers and value category of another type. * @tparam _Tp An lvalue reference or rvalue reference. * @tparam _Up An lvalue reference type deduced from the function argument. @@ -174,7 +174,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION [[__nodiscard__,__gnu__::__always_inline__]] inline _GLIBCXX17_CONSTEXPR _Tp* addressof(_Tp& __r) noexcept - { return std::__addressof(__r); } + { return __builtin_addressof(__r); } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2598. addressof works on temporaries @@ -215,14 +215,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @return Nothing. */ template<typename _Tp> - _GLIBCXX20_CONSTEXPR - inline -#if __cplusplus >= 201103L - typename enable_if<__and_<__not_<__is_tuple_like<_Tp>>, - is_move_constructible<_Tp>, - is_move_assignable<_Tp>>::value>::type +#if __glibcxx_concepts // >= C++20 + requires (! __is_tuple_like<_Tp>::value) + && is_move_constructible_v<_Tp> + && is_move_assignable_v<_Tp> + constexpr void +#elif __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR inline + __enable_if_t<__and_<__not_<__is_tuple_like<_Tp>>, + is_move_constructible<_Tp>, + is_move_assignable<_Tp>>::value> #else - void + inline void #endif swap(_Tp& __a, _Tp& __b) _GLIBCXX_NOEXCEPT_IF(__and_<is_nothrow_move_constructible<_Tp>, @@ -241,12 +245,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // DR 809. std::swap should be overloaded for array types. /// Swap the contents of two arrays. template<typename _Tp, size_t _Nm> - _GLIBCXX20_CONSTEXPR - inline -#if __cplusplus >= 201103L - typename enable_if<__is_swappable<_Tp>::value>::type +#if __glibcxx_concepts // >= C++20 + requires is_swappable_v<_Tp> + constexpr void +#elif __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR inline + __enable_if_t<__is_swappable<_Tp>::value> #else - void + inline void #endif swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm]) _GLIBCXX_NOEXCEPT_IF(__is_nothrow_swappable<_Tp>::value) 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/ostream.h b/libstdc++-v3/include/bits/ostream.h index d19a76a..caa47be 100644 --- a/libstdc++-v3/include/bits/ostream.h +++ b/libstdc++-v3/include/bits/ostream.h @@ -499,9 +499,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif __sign = __builtin_signbit(__f) ? _To(-1.0) : _To(+1.0); - if _GLIBCXX17_CONSTEXPR (__is_same(_To, double)) + if _GLIBCXX_CONSTEXPR (__is_same(_To, double)) __d = __builtin_copysign(__d, __sign); - else if _GLIBCXX17_CONSTEXPR (__is_same(_To, long double)) + else if _GLIBCXX_CONSTEXPR (__is_same(_To, long double)) __d = __builtin_copysignl(__d, __sign); #endif return __d; diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h index d3c1765..91da88b 100644 --- a/libstdc++-v3/include/bits/ptr_traits.h +++ b/libstdc++-v3/include/bits/ptr_traits.h @@ -36,7 +36,7 @@ #if __cplusplus > 201703L #include <concepts> -namespace __gnu_debug { struct _Safe_iterator_base; } +namespace __gnu_debug { class _Safe_iterator_base; } #endif namespace std _GLIBCXX_VISIBILITY(default) @@ -223,7 +223,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /** * @brief Obtain address referenced by a pointer to an object * @param __ptr A pointer to an object - * @return @c __ptr + * @return `__ptr` * @ingroup pointer_abstractions */ template<typename _Tp> @@ -239,8 +239,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /** * @brief Obtain address referenced by a pointer to an object * @param __ptr A pointer to an object - * @return @c pointer_traits<_Ptr>::to_address(__ptr) if that expression is - well-formed, otherwise @c to_address(__ptr.operator->()) + * @return `pointer_traits<_Ptr>::to_address(__ptr)` if that expression is + * well-formed, otherwise `to_address(__ptr.operator->())`. * @ingroup pointer_abstractions */ template<typename _Ptr> diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc index 752d707..53ccacb 100644 --- a/libstdc++-v3/include/bits/random.tcc +++ b/libstdc++-v3/include/bits/random.tcc @@ -849,11 +849,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr result_type __range = max() - min(); size_t __j = __k; const result_type __y = _M_y - min(); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr // Avoid using slower long double arithmetic if possible. - if _GLIBCXX17_CONSTEXPR (__detail::__p1_representable_as_double(__range)) + if constexpr (__detail::__p1_representable_as_double(__range)) __j *= __y / (__range + 1.0); else __j *= __y / (__range + 1.0L); +#pragma GCC diagnostic pop _M_y = _M_v[__j]; _M_v[__j] = _M_b(); @@ -3244,8 +3247,11 @@ namespace __detail template<typename _InputIterator> seed_seq::seed_seq(_InputIterator __begin, _InputIterator __end) { - if _GLIBCXX17_CONSTEXPR (__is_random_access_iter<_InputIterator>::value) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + if constexpr (__is_random_access_iter<_InputIterator>::value) _M_v.reserve(std::distance(__begin, __end)); +#pragma GCC diagnostic pop for (_InputIterator __iter = __begin; __iter != __end; ++__iter) _M_v.push_back(__detail::__mod<result_type, diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index f36e7dd..9b348d8 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 @@ -76,7 +109,7 @@ namespace ranges template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Proj = identity, indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { @@ -89,7 +122,7 @@ namespace ranges template<input_range _Range, typename _Proj = identity, indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -104,7 +137,7 @@ namespace ranges template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Proj = identity, indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { @@ -117,7 +150,7 @@ namespace ranges template<input_range _Range, typename _Proj = identity, indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -132,7 +165,7 @@ namespace ranges template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Proj = identity, indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { @@ -145,7 +178,7 @@ namespace ranges template<input_range _Range, typename _Proj = identity, indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -246,7 +279,7 @@ namespace ranges typename _Pred = ranges::equal_to, typename _Proj1 = identity, typename _Proj2 = identity> requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> - constexpr _Iter1 + [[nodiscard]] constexpr _Iter1 operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const @@ -265,7 +298,7 @@ namespace ranges typename _Proj1 = identity, typename _Proj2 = identity> requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> - constexpr borrowed_iterator_t<_Range1> + [[nodiscard]] constexpr borrowed_iterator_t<_Range1> operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { @@ -286,7 +319,7 @@ namespace ranges requires indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>, const _Tp*> - constexpr iter_difference_t<_Iter> + [[nodiscard]] constexpr iter_difference_t<_Iter> operator()(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {}) const { @@ -303,7 +336,7 @@ namespace ranges requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _Tp*> - constexpr range_difference_t<_Range> + [[nodiscard]] constexpr range_difference_t<_Range> operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -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, @@ -445,7 +726,7 @@ namespace ranges typename _Pred = ranges::equal_to, typename _Proj1 = identity, typename _Proj2 = identity> requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> - constexpr subrange<_Iter1> + [[nodiscard]] constexpr subrange<_Iter1> operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const @@ -502,7 +783,7 @@ namespace ranges typename _Proj1 = identity, typename _Proj2 = identity> requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> - constexpr borrowed_subrange_t<_Range1> + [[nodiscard]] constexpr borrowed_subrange_t<_Range1> operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { @@ -525,7 +806,7 @@ namespace ranges indirect_equivalence_relation<projected<_Iter1, _Proj1>, projected<_Iter2, _Proj2>> _Pred = ranges::equal_to> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const @@ -594,7 +875,7 @@ namespace ranges indirect_equivalence_relation< projected<iterator_t<_Range1>, _Proj1>, projected<iterator_t<_Range2>, _Proj2>> _Pred = ranges::equal_to> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { @@ -1000,7 +1281,7 @@ namespace ranges template<permutable _Iter, sentinel_for<_Iter> _Sent, typename _Proj = identity, indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> - constexpr subrange<_Iter> + [[nodiscard]] constexpr subrange<_Iter> operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { @@ -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; } @@ -1024,7 +1305,7 @@ namespace ranges indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred> requires permutable<iterator_t<_Range>> - constexpr borrowed_subrange_t<_Range> + [[nodiscard]] constexpr borrowed_subrange_t<_Range> operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -1042,7 +1323,7 @@ namespace ranges requires indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>, const _Tp*> - constexpr subrange<_Iter> + [[nodiscard]] constexpr subrange<_Iter> operator()(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {}) const { @@ -1060,7 +1341,7 @@ namespace ranges && indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _Tp*> - constexpr borrowed_subrange_t<_Range> + [[nodiscard]] constexpr borrowed_subrange_t<_Range> operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -1159,7 +1440,7 @@ namespace ranges typename _Proj = identity, indirect_equivalence_relation< projected<_Iter, _Proj>> _Comp = ranges::equal_to> - constexpr subrange<_Iter> + [[nodiscard]] constexpr subrange<_Iter> operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { @@ -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}; } @@ -1181,7 +1462,7 @@ namespace ranges indirect_equivalence_relation< projected<iterator_t<_Range>, _Proj>> _Comp = ranges::equal_to> requires permutable<iterator_t<_Range>> - constexpr borrowed_subrange_t<_Range> + [[nodiscard]] constexpr borrowed_subrange_t<_Range> operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -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; @@ -1399,9 +1683,11 @@ namespace ranges if constexpr (__is_pod(iter_value_t<_Iter>)) if (__k == 1) { - auto __t = std::move(*__p); - ranges::move(__p + 1, __p + __n, __p); - *(__p + __n - 1) = std::move(__t); + auto __mid = ranges::next(__p, __n - 1); + auto __end = ranges::next(__mid); + auto __t = ranges::iter_move(__p); + ranges::move(ranges::next(__p), __end, __p); + *__mid = std::move(__t); return {std::move(__ret), std::move(__lasti)}; } auto __q = __p + __k; @@ -1425,8 +1711,10 @@ namespace ranges if constexpr (__is_pod(iter_value_t<_Iter>)) if (__k == 1) { - auto __t = std::move(*(__p + __n - 1)); - ranges::move_backward(__p, __p + __n - 1, __p + __n); + auto __mid = ranges::next(__p, __n - 1); + auto __end = ranges::next(__mid); + auto __t = ranges::iter_move(__mid); + ranges::move_backward(__p, __mid, __end); *__p = std::move(__t); return {std::move(__ret), std::move(__lasti)}; } @@ -1555,14 +1843,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 +1927,7 @@ namespace ranges if (__k < __n) __out[__k] = *__first; } - return __out + __sample_sz; + return __out + iter_difference_t<_Out>(__sample_sz); } } @@ -1612,9 +1956,63 @@ 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 = ranges::next(__first); + + // 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++, ranges::next(__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<_DistanceType, _DistanceType> __pospos = + __gen_two_uniform_ints(__swap_range, __swap_range + 1, __g); + + ranges::iter_swap(__i++, ranges::next(__first, __pospos.first)); + ranges::iter_swap(__i++, ranges::next(__first, __pospos.second)); + } + + return __i; + } + + __distr_type __d; + + _Iter __i = ranges::next(__first); + for (; __i != __last; ++__i) + ranges::iter_swap(__i, + ranges::next(__first, + __d(__g, __p_type(0, __i - __first)))); + + return __i; } template<random_access_range _Range, typename _Gen> @@ -1630,6 +2028,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 +2059,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(ranges::prev(__last)), + __comp_proj); + return __last; + } } template<random_access_range _Range, @@ -1658,6 +2085,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 +2136,19 @@ 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 __back = ranges::prev(__last); + auto __comp_proj = __detail::__make_comp_proj(__comp, __proj); + __detail::__pop_heap(__first, __back, __back, __comp_proj); + } + return __last; + } } template<random_access_range _Range, @@ -1695,10 +2173,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 +2220,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 +2316,157 @@ 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 = ranges::next(__first); __i != __last; ++__i) + { + if (__comp(*__i, *__first)) + { + iter_value_t<_Iter> __val = ranges::iter_move(__i); + ranges::move_backward(__first, __i, ranges::next(__i)); + *__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) + { + constexpr iter_difference_t<_Iter> __threshold = __sort_threshold; + if (__last - __first > __threshold) + { + __detail::__insertion_sort(__first, __first + __threshold, __comp); + __detail::__unguarded_insertion_sort(__first + __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, ranges::next(__first), __mid, + ranges::prev(__last), __comp); + return __detail::__unguarded_partition(ranges::next(__first), __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 +2476,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 +2506,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 +2679,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, @@ -1887,7 +2755,7 @@ namespace ranges std::__invoke(__proj, *__first))) { ranges::pop_heap(__first, __middle, __comp, __proj); - ranges::iter_swap(__middle-1, __i); + ranges::iter_swap(std::prev(__middle), __i); ranges::push_heap(__first, __middle, __comp, __proj); } ranges::sort_heap(__first, __middle, __comp, __proj); @@ -1954,7 +2822,7 @@ namespace ranges { ranges::pop_heap(__result_first, __result_real_last, __comp, __proj2); - *(__result_real_last-1) = *__first; + *ranges::prev(__result_real_last) = *__first; ranges::push_heap(__result_first, __result_real_last, __comp, __proj2); } @@ -1991,7 +2859,7 @@ namespace ranges typename _Proj = identity, indirect_strict_weak_order<projected<_Iter, _Proj>> _Comp = ranges::less> - constexpr _Iter + [[nodiscard]] constexpr _Iter operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2010,7 +2878,7 @@ namespace ranges template<forward_range _Range, typename _Proj = identity, indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> - constexpr borrowed_iterator_t<_Range> + [[nodiscard]] constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -2026,7 +2894,7 @@ namespace ranges typename _Proj = identity, indirect_strict_weak_order<projected<_Iter, _Proj>> _Comp = ranges::less> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2045,7 +2913,7 @@ namespace ranges template<forward_range _Range, typename _Proj = identity, indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -2055,6 +2923,34 @@ 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, ranges::next(__nth), __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 +2960,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, @@ -2092,7 +2998,7 @@ namespace ranges typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj), indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>> _Comp = ranges::less> - constexpr _Iter + [[nodiscard]] constexpr _Iter operator()(_Iter __first, _Sent __last, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2122,7 +3028,7 @@ namespace ranges indirect_strict_weak_order<const _Tp*, projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> - constexpr borrowed_iterator_t<_Range> + [[nodiscard]] constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2140,7 +3046,7 @@ namespace ranges typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj), indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>> _Comp = ranges::less> - constexpr _Iter + [[nodiscard]] constexpr _Iter operator()(_Iter __first, _Sent __last, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2170,7 +3076,7 @@ namespace ranges indirect_strict_weak_order<const _Tp*, projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> - constexpr borrowed_iterator_t<_Range> + [[nodiscard]] constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2188,7 +3094,7 @@ namespace ranges typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj), indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>> _Comp = ranges::less> - constexpr subrange<_Iter> + [[nodiscard]] constexpr subrange<_Iter> operator()(_Iter __first, _Sent __last, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2233,7 +3139,7 @@ namespace ranges indirect_strict_weak_order<const _Tp*, projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> - constexpr borrowed_subrange_t<_Range> + [[nodiscard]] constexpr borrowed_subrange_t<_Range> operator()(_Range&& __r, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2251,7 +3157,7 @@ namespace ranges typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj), indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>> _Comp = ranges::less> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Iter __first, _Sent __last, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2269,7 +3175,7 @@ namespace ranges indirect_strict_weak_order<const _Tp*, projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Range&& __r, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2285,7 +3191,7 @@ namespace ranges template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Proj = identity, indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { @@ -2301,7 +3207,7 @@ namespace ranges template<input_range _Range, typename _Proj = identity, indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -2383,6 +3289,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 +3374,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, @@ -2497,7 +3499,7 @@ namespace ranges template<forward_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Proj = identity, indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> - constexpr _Iter + [[nodiscard]] constexpr _Iter operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { @@ -2523,7 +3525,7 @@ namespace ranges template<forward_range _Range, typename _Proj = identity, indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred> - constexpr borrowed_iterator_t<_Range> + [[nodiscard]] constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -2594,6 +3596,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 +3816,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, @@ -2635,7 +3886,7 @@ namespace ranges indirect_strict_weak_order<projected<_Iter1, _Proj1>, projected<_Iter2, _Proj2>> _Comp = ranges::less> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Comp __comp = {}, @@ -2664,7 +3915,7 @@ namespace ranges indirect_strict_weak_order<projected<iterator_t<_Range1>, _Proj1>, projected<iterator_t<_Range2>, _Proj2>> _Comp = ranges::less> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Range1&& __r1, _Range2&& __r2, _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { @@ -2935,7 +4186,7 @@ namespace ranges template<typename _Tp, typename _Proj = identity, indirect_strict_weak_order<projected<const _Tp*, _Proj>> _Comp = ranges::less> - constexpr const _Tp& + [[nodiscard]] constexpr const _Tp& operator()(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2952,7 +4203,7 @@ namespace ranges _Comp = ranges::less> requires indirectly_copyable_storable<iterator_t<_Range>, range_value_t<_Range>*> - constexpr range_value_t<_Range> + [[nodiscard]] constexpr range_value_t<_Range> operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { auto __first = ranges::begin(__r); @@ -2973,7 +4224,7 @@ namespace ranges template<copyable _Tp, typename _Proj = identity, indirect_strict_weak_order<projected<const _Tp*, _Proj>> _Comp = ranges::less> - constexpr _Tp + [[nodiscard]] constexpr _Tp operator()(initializer_list<_Tp> __r, _Comp __comp = {}, _Proj __proj = {}) const { @@ -2989,7 +4240,7 @@ namespace ranges template<typename _Tp, typename _Proj = identity, indirect_strict_weak_order<projected<const _Tp*, _Proj>> _Comp = ranges::less> - constexpr const _Tp& + [[nodiscard]] constexpr const _Tp& operator()(const _Tp& __val, const _Tp& __lo, const _Tp& __hi, _Comp __comp = {}, _Proj __proj = {}) const { @@ -3039,7 +4290,7 @@ namespace ranges template<typename _Tp, typename _Proj = identity, indirect_strict_weak_order<projected<const _Tp*, _Proj>> _Comp = ranges::less> - constexpr minmax_result<const _Tp&> + [[nodiscard]] constexpr minmax_result<const _Tp&> operator()(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) const { @@ -3055,7 +4306,7 @@ namespace ranges indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> requires indirectly_copyable_storable<iterator_t<_Range>, range_value_t<_Range>*> - constexpr minmax_result<range_value_t<_Range>> + [[nodiscard]] constexpr minmax_result<range_value_t<_Range>> operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { auto __first = ranges::begin(__r); @@ -3114,7 +4365,7 @@ namespace ranges template<copyable _Tp, typename _Proj = identity, indirect_strict_weak_order<projected<const _Tp*, _Proj>> _Comp = ranges::less> - constexpr minmax_result<_Tp> + [[nodiscard]] constexpr minmax_result<_Tp> operator()(initializer_list<_Tp> __r, _Comp __comp = {}, _Proj __proj = {}) const { @@ -3131,7 +4382,7 @@ namespace ranges typename _Proj = identity, indirect_strict_weak_order<projected<_Iter, _Proj>> _Comp = ranges::less> - constexpr _Iter + [[nodiscard]] constexpr _Iter operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { @@ -3152,7 +4403,7 @@ namespace ranges template<forward_range _Range, typename _Proj = identity, indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> - constexpr borrowed_iterator_t<_Range> + [[nodiscard]] constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -3168,7 +4419,7 @@ namespace ranges typename _Proj = identity, indirect_strict_weak_order<projected<_Iter, _Proj>> _Comp = ranges::less> - constexpr _Iter + [[nodiscard]] constexpr _Iter operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { @@ -3189,7 +4440,7 @@ namespace ranges template<forward_range _Range, typename _Proj = identity, indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> - constexpr borrowed_iterator_t<_Range> + [[nodiscard]] constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -3208,7 +4459,7 @@ namespace ranges typename _Proj = identity, indirect_strict_weak_order<projected<_Iter, _Proj>> _Comp = ranges::less> - constexpr minmax_element_result<_Iter> + [[nodiscard]] constexpr minmax_element_result<_Iter> operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { @@ -3263,7 +4514,7 @@ namespace ranges template<forward_range _Range, typename _Proj = identity, indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> - constexpr minmax_element_result<borrowed_iterator_t<_Range>> + [[nodiscard]] constexpr minmax_element_result<borrowed_iterator_t<_Range>> operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -3281,7 +4532,7 @@ namespace ranges indirect_strict_weak_order<projected<_Iter1, _Proj1>, projected<_Iter2, _Proj2>> _Comp = ranges::less> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Comp __comp = {}, @@ -3367,7 +4618,7 @@ namespace ranges indirect_strict_weak_order<projected<iterator_t<_Range1>, _Proj1>, projected<iterator_t<_Range2>, _Proj2>> _Comp = ranges::less> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Range1&& __r1, _Range2&& __r2, _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { @@ -3596,7 +4847,7 @@ namespace ranges typename _Proj = identity, typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj)> requires indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>, const _Tp*> - constexpr subrange<_Iter> + [[nodiscard]] constexpr subrange<_Iter> operator()(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {}) const { if constexpr (same_as<_Iter, _Sent> && bidirectional_iterator<_Iter>) @@ -3629,7 +4880,7 @@ namespace ranges typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj)> requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _Tp*> - constexpr borrowed_subrange_t<_Range> + [[nodiscard]] constexpr borrowed_subrange_t<_Range> operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), __value, std::move(__proj)); } }; @@ -3640,7 +4891,7 @@ namespace ranges { template<forward_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Proj = identity, indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> - constexpr subrange<_Iter> + [[nodiscard]] constexpr subrange<_Iter> operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { if constexpr (same_as<_Iter, _Sent> && bidirectional_iterator<_Iter>) @@ -3671,7 +4922,7 @@ namespace ranges template<forward_range _Range, typename _Proj = identity, indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred> - constexpr borrowed_subrange_t<_Range> + [[nodiscard]] constexpr borrowed_subrange_t<_Range> operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__pred), std::move(__proj)); } }; @@ -3682,7 +4933,7 @@ namespace ranges { template<forward_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Proj = identity, indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> - constexpr subrange<_Iter> + [[nodiscard]] constexpr subrange<_Iter> operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { if constexpr (same_as<_Iter, _Sent> && bidirectional_iterator<_Iter>) @@ -3713,7 +4964,7 @@ namespace ranges template<forward_range _Range, typename _Proj = identity, indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred> - constexpr borrowed_subrange_t<_Range> + [[nodiscard]] constexpr borrowed_subrange_t<_Range> operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__pred), std::move(__proj)); } }; @@ -3978,6 +5229,7 @@ namespace ranges #endif // __glibcxx_ranges_fold } // namespace ranges +#if __glibcxx_shift >= 201806L // C++ >= 20 template<typename _ForwardIterator> constexpr _ForwardIterator shift_left(_ForwardIterator __first, _ForwardIterator __last, @@ -4068,6 +5320,120 @@ namespace ranges } } } +#endif + +namespace ranges +{ +#if __glibcxx_shift >= 202202L // C++ >= 23 + struct __shift_left_fn + { + template<permutable _Iter, sentinel_for<_Iter> _Sent> + constexpr subrange<_Iter> + operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> __n) const + { + __glibcxx_assert(__n >= 0); + if (__n == 0) + return {__first, ranges::next(__first, __last)}; + + auto __mid = ranges::next(__first, __n, __last); + if (__mid == __last) + return {__first, __first}; + return {__first, ranges::move(__mid, __last, __first).out}; + } + + template<forward_range _Range> + requires permutable<iterator_t<_Range>> + constexpr borrowed_subrange_t<_Range> + operator()(_Range&& __r, range_difference_t<_Range> __n) const + { return (*this)(ranges::begin(__r), ranges::end(__r), __n); } + }; + + inline constexpr __shift_left_fn shift_left{}; + + struct __shift_right_fn + { + template<permutable _Iter, sentinel_for<_Iter> _Sent> + constexpr subrange<_Iter> + operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> __n) const + { + __glibcxx_assert(__n >= 0); + if (__n == 0) + return {__first, ranges::next(__first, __last)}; + + if constexpr (bidirectional_iterator<_Iter> && same_as<_Iter, _Sent>) + { + auto __mid = ranges::next(__last, -__n, __first); + if (__mid == __first) + return {__last, __last}; + + return {ranges::move_backward(__first, __mid, __last).out, __last}; + } + else + { + auto __result = ranges::next(__first, __n, __last); + if (__result == __last) + return {__result, __result}; + + auto __dest_head = __first, __dest_tail = __result; + while (__dest_head != __result) + { + if (__dest_tail == __last) + { + // If we get here, then we must have + // 2*n >= distance(__first, __last) + // i.e. we are shifting out at least half of the range. In + // this case we can safely perform the shift with a single + // move. + auto __lasti = ranges::move(__first, __dest_head, __result).out; + // __glibcxx_assert(__lasti == __last); + return {__result, __lasti}; + } + ++__dest_head; + ++__dest_tail; + } + + for (;;) + { + // At the start of each iteration of this outer loop, the range + // [__first, __result) contains those elements that after shifting + // the whole range right by __n, should end up in + // [__dest_head, __dest_tail) in order. + + // The below inner loop swaps the elements of [__first, __result) + // and [__dest_head, __dest_tail), while simultaneously shifting + // the latter range by __n. + auto __cursor = __first; + while (__cursor != __result) + { + if (__dest_tail == __last) + { + // At this point the ranges [__first, result) and + // [__dest_head, dest_tail) are disjoint, so we can safely + // move the remaining elements. + __dest_head = ranges::move(__cursor, __result, __dest_head).out; + auto __lasti = ranges::move(__first, __cursor, __dest_head).out; + // __glibcxx_assert(__lasti == __last); + return {__result, __lasti}; + } + ranges::iter_swap(__cursor, __dest_head); + ++__dest_head; + ++__dest_tail; + ++__cursor; + } + } + } + } + + template<forward_range _Range> + requires permutable<iterator_t<_Range>> + constexpr borrowed_subrange_t<_Range> + operator()(_Range&& __r, range_difference_t<_Range> __n) const + { return (*this)(ranges::begin(__r), ranges::end(__r), __n); } + }; + + inline constexpr __shift_right_fn shift_right{}; +#endif // C++23 +} // namespace ranges _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h index a08f659b..45ed5b4 100644 --- a/libstdc++-v3/include/bits/ranges_algobase.h +++ b/libstdc++-v3/include/bits/ranges_algobase.h @@ -101,7 +101,7 @@ namespace ranges typename _Pred = ranges::equal_to, typename _Proj1 = identity, typename _Proj2 = identity> requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const @@ -168,7 +168,7 @@ namespace ranges typename _Proj1 = identity, typename _Proj2 = identity> requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> - constexpr bool + [[nodiscard]] constexpr bool operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index 488907d..1c4bf43 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -68,29 +68,22 @@ namespace ranges namespace __detail { + [[__gnu__::__always_inline__]] constexpr __max_size_type __to_unsigned_like(__max_size_type __t) noexcept { return __t; } + [[__gnu__::__always_inline__]] constexpr __max_size_type __to_unsigned_like(__max_diff_type __t) noexcept { return __max_size_type(__t); } template<integral _Tp> + [[__gnu__::__always_inline__]] constexpr auto __to_unsigned_like(_Tp __t) noexcept { return static_cast<make_unsigned_t<_Tp>>(__t); } -#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ - constexpr unsigned __int128 - __to_unsigned_like(__int128 __t) noexcept - { return __t; } - - constexpr unsigned __int128 - __to_unsigned_like(unsigned __int128 __t) noexcept - { return __t; } -#endif - template<typename _Tp> using __make_unsigned_like_t = decltype(__detail::__to_unsigned_like(std::declval<_Tp>())); @@ -113,23 +106,24 @@ namespace ranges { private: template<typename _Tp> - static constexpr bool + static consteval bool _S_noexcept() { 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: template<__maybe_borrowed_range _Tp> requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp> || __adl_begin<_Tp> + [[nodiscard, __gnu__::__always_inline__]] constexpr auto - operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) { if constexpr (is_array_v<remove_reference_t<_Tp>>) { @@ -146,7 +140,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,30 +150,31 @@ 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 { private: template<typename _Tp> - static constexpr bool + static consteval bool _S_noexcept() { 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: template<__maybe_borrowed_range _Tp> requires is_bounded_array_v<remove_reference_t<_Tp>> || __member_end<_Tp> || __adl_end<_Tp> + [[nodiscard, __gnu__::__always_inline__]] constexpr auto - operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) { if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>) { @@ -196,7 +191,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 +200,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> @@ -219,13 +214,13 @@ namespace ranges { private: template<typename _Tp> - static constexpr bool + static consteval bool _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&>()))) @@ -242,8 +237,9 @@ namespace ranges public: template<__maybe_borrowed_range _Tp> requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp> + [[nodiscard, __gnu__::__always_inline__]] constexpr auto - operator()[[nodiscard]](_Tp&& __t) const + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) { if constexpr (__member_rbegin<_Tp>) @@ -258,7 +254,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 +264,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)))>; }; @@ -276,13 +272,13 @@ namespace ranges { private: template<typename _Tp> - static constexpr bool + static consteval bool _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&>()))) @@ -299,8 +295,9 @@ namespace ranges public: template<__maybe_borrowed_range _Tp> requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp> + [[nodiscard, __gnu__::__always_inline__]] constexpr auto - operator()[[nodiscard]](_Tp&& __t) const + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) { if constexpr (__member_rend<_Tp>) @@ -316,7 +313,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 +323,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> @@ -345,15 +342,15 @@ namespace ranges { private: template<typename _Tp> - static constexpr bool + static consteval bool _S_noexcept() { 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&>())); @@ -363,8 +360,9 @@ namespace ranges template<typename _Tp> requires is_bounded_array_v<remove_reference_t<_Tp>> || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp> + [[nodiscard, __gnu__::__always_inline__]] constexpr auto - operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) { if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>) return extent_v<remove_reference_t<_Tp>>; @@ -383,8 +381,9 @@ namespace ranges // 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E) template<typename _Tp> requires requires (_Tp& __t) { _Size{}(__t); } + [[nodiscard, __gnu__::__always_inline__]] constexpr auto - operator()[[nodiscard]](_Tp&& __t) const noexcept(noexcept(_Size{}(__t))) + operator()(_Tp&& __t) const noexcept(noexcept(_Size{}(__t))) { auto __size = _Size{}(__t); using __size_type = decltype(__size); @@ -398,11 +397,6 @@ namespace ranges else return static_cast<make_signed_t<__size_type>>(__size); } -#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ - // For strict-ansi modes integral<__int128> is false - else if constexpr (__detail::__is_int128<__size_type>) - return static_cast<__int128>(__size); -#endif else // Must be one of __max_diff_type or __max_size_type. return __detail::__max_diff_type(__size); } @@ -428,7 +422,7 @@ namespace ranges { private: template<typename _Tp> - static constexpr bool + static consteval bool _S_noexcept() { if constexpr (__member_empty<_Tp>) @@ -444,8 +438,9 @@ namespace ranges template<typename _Tp> requires __member_empty<_Tp> || __size0_empty<_Tp> || __eq_iter_empty<_Tp> + [[nodiscard, __gnu__::__always_inline__]] constexpr bool - operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) { if constexpr (__member_empty<_Tp>) return bool(__t.empty()); @@ -463,7 +458,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> @@ -473,11 +468,11 @@ namespace ranges { private: template<typename _Tp> - static constexpr bool + static consteval bool _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&>())); } @@ -485,8 +480,9 @@ namespace ranges public: template<__maybe_borrowed_range _Tp> requires __member_data<_Tp> || __begin_data<_Tp> + [[nodiscard, __gnu__::__always_inline__]] constexpr auto - operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp>()) + operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>()) { if constexpr (__member_data<_Tp>) return __t.data(); @@ -647,6 +643,7 @@ namespace ranges { #if __glibcxx_ranges_as_const // >= C++23 template<input_range _Range> + [[__gnu__::__always_inline__]] constexpr auto& __possibly_const_range(_Range& __r) noexcept { @@ -660,6 +657,7 @@ namespace ranges #else // If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&. template<typename _To, typename _Tp> + [[__gnu__::__always_inline__]] constexpr decltype(auto) __as_const(_Tp& __t) noexcept { @@ -894,10 +892,17 @@ namespace ranges { if constexpr (sized_sentinel_for<_Sent, _It>) { - const auto __diff = __bound - __it; + const iter_difference_t<_It> __diff = __bound - __it; if (__diff == 0) - return __n; + { + // inline any possible side effects of advance(it, bound) + if constexpr (assignable_from<_It&, _Sent>) + __it = std::move(__bound); + else if constexpr (random_access_iterator<_It>) + __it += iter_difference_t<_It>(0); + return __n; + } else if (__diff > 0 ? __n >= __diff : __n <= __diff) { (*this)(__it, __bound); @@ -912,9 +917,14 @@ namespace ranges return 0; } else - return 0; + { + // inline any possible side effects of advance(it, n) + if constexpr (random_access_iterator<_It>) + __it += iter_difference_t<_It>(0); + return 0; + } } - else if (__it == __bound || __n == 0) + else if (__n == 0 || __it == __bound) return __n; else if (__n > 0) { @@ -970,13 +980,13 @@ namespace ranges } template<typename _It, sized_sentinel_for<decay_t<_It>> _Sent> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr iter_difference_t<decay_t<_It>> operator()(_It&& __first, _Sent __last) const { return __last - static_cast<const decay_t<_It>&>(__first); } template<range _Range> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr range_difference_t<_Range> operator()(_Range&& __r) const { @@ -994,7 +1004,7 @@ namespace ranges struct __next_fn final { template<input_or_output_iterator _It> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr _It operator()(_It __x) const { @@ -1003,7 +1013,7 @@ namespace ranges } template<input_or_output_iterator _It> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr _It operator()(_It __x, iter_difference_t<_It> __n) const { @@ -1012,7 +1022,7 @@ namespace ranges } template<input_or_output_iterator _It, sentinel_for<_It> _Sent> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr _It operator()(_It __x, _Sent __bound) const { @@ -1021,7 +1031,7 @@ namespace ranges } template<input_or_output_iterator _It, sentinel_for<_It> _Sent> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr _It operator()(_It __x, iter_difference_t<_It> __n, _Sent __bound) const { @@ -1037,7 +1047,7 @@ namespace ranges struct __prev_fn final { template<bidirectional_iterator _It> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr _It operator()(_It __x) const { @@ -1046,7 +1056,7 @@ namespace ranges } template<bidirectional_iterator _It> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr _It operator()(_It __x, iter_difference_t<_It> __n) const { @@ -1055,7 +1065,7 @@ namespace ranges } template<bidirectional_iterator _It> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr _It operator()(_It __x, iter_difference_t<_It> __n, _It __bound) const { @@ -1103,11 +1113,11 @@ namespace __detail // 4223. Deduction guides for maps are mishandling tuples and references template<ranges::input_range _Range> using __range_key_type - = remove_const_t<tuple_element_t<0, ranges::range_value_t<_Range>>>; + = remove_cvref_t<tuple_element_t<0, ranges::range_value_t<_Range>>>; template<ranges::input_range _Range> using __range_mapped_type - = tuple_element_t<1, ranges::range_value_t<_Range>>; + = remove_cvref_t<tuple_element_t<1, ranges::range_value_t<_Range>>>; // The allocator's value_type for map-like containers. template<ranges::input_range _Range> diff --git a/libstdc++-v3/include/bits/ranges_uninitialized.h b/libstdc++-v3/include/bits/ranges_uninitialized.h index 12a714b..3f9a07f 100644 --- a/libstdc++-v3/include/bits/ranges_uninitialized.h +++ b/libstdc++-v3/include/bits/ranges_uninitialized.h @@ -556,13 +556,12 @@ namespace ranges __destroy_fn::operator()(_Iter __first, _Sent __last) const noexcept { if constexpr (is_trivially_destructible_v<iter_value_t<_Iter>>) - return ranges::next(std::move(__first), __last); - else - { - for (; __first != __last; ++__first) - ranges::destroy_at(std::__addressof(*__first)); - return __first; - } + if (!is_constant_evaluated()) + return ranges::next(std::move(__first), __last); + + for (; __first != __last; ++__first) + ranges::destroy_at(std::__addressof(*__first)); + return __first; } template<__detail::__nothrow_input_range _Range> @@ -581,13 +580,12 @@ namespace ranges operator()(_Iter __first, iter_difference_t<_Iter> __n) const noexcept { if constexpr (is_trivially_destructible_v<iter_value_t<_Iter>>) - return ranges::next(std::move(__first), __n); - else - { - for (; __n > 0; ++__first, (void)--__n) - ranges::destroy_at(std::__addressof(*__first)); - return __first; - } + if (!is_constant_evaluated()) + return ranges::next(std::move(__first), __n); + + for (; __n > 0; ++__first, (void)--__n) + ranges::destroy_at(std::__addressof(*__first)); + return __first; } }; diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index 53b7f5c..84de258 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -501,7 +501,7 @@ namespace ranges typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj)> requires indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>, const _Tp*> - constexpr _Iter + [[nodiscard]] constexpr _Iter operator()(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {}) const { @@ -537,7 +537,7 @@ namespace ranges requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _Tp*> - constexpr borrowed_iterator_t<_Range> + [[nodiscard]] constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -552,7 +552,7 @@ namespace ranges template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Proj = identity, indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> - constexpr _Iter + [[nodiscard]] constexpr _Iter operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { @@ -565,7 +565,7 @@ namespace ranges template<input_range _Range, typename _Proj = identity, indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred> - constexpr borrowed_iterator_t<_Range> + [[nodiscard]] constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -580,7 +580,7 @@ namespace ranges template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Proj = identity, indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> - constexpr _Iter + [[nodiscard]] constexpr _Iter operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { @@ -593,7 +593,7 @@ namespace ranges template<input_range _Range, typename _Proj = identity, indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred> - constexpr borrowed_iterator_t<_Range> + [[nodiscard]] constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), @@ -634,7 +634,7 @@ namespace ranges typename _Pred = ranges::equal_to, typename _Proj1 = identity, typename _Proj2 = identity> requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> - constexpr mismatch_result<_Iter1, _Iter2> + [[nodiscard]] constexpr mismatch_result<_Iter1, _Iter2> operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const @@ -655,6 +655,7 @@ namespace ranges typename _Proj1 = identity, typename _Proj2 = identity> requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> + [[nodiscard]] constexpr mismatch_result<iterator_t<_Range1>, iterator_t<_Range2>> operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const @@ -675,7 +676,7 @@ namespace ranges typename _Pred = ranges::equal_to, typename _Proj1 = identity, typename _Proj2 = identity> requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> - constexpr subrange<_Iter1> + [[nodiscard]] constexpr subrange<_Iter1> operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const @@ -719,7 +720,7 @@ namespace ranges typename _Proj1 = identity, typename _Proj2 = identity> requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> - constexpr borrowed_subrange_t<_Range1> + [[nodiscard]] constexpr borrowed_subrange_t<_Range1> operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { @@ -737,7 +738,7 @@ namespace ranges template<typename _Tp, typename _Proj = identity, indirect_strict_weak_order<projected<const _Tp*, _Proj>> _Comp = ranges::less> - constexpr const _Tp& + [[nodiscard]] constexpr const _Tp& operator()(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) const { @@ -754,7 +755,7 @@ namespace ranges _Comp = ranges::less> requires indirectly_copyable_storable<iterator_t<_Range>, range_value_t<_Range>*> - constexpr range_value_t<_Range> + [[nodiscard]] constexpr range_value_t<_Range> operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { auto __first = ranges::begin(__r); @@ -775,7 +776,7 @@ namespace ranges template<copyable _Tp, typename _Proj = identity, indirect_strict_weak_order<projected<const _Tp*, _Proj>> _Comp = ranges::less> - constexpr _Tp + [[nodiscard]] constexpr _Tp operator()(initializer_list<_Tp> __r, _Comp __comp = {}, _Proj __proj = {}) const { @@ -793,7 +794,7 @@ namespace ranges indirect_binary_predicate<projected<_Iter, _Proj>, projected<_Iter, _Proj>> _Pred = ranges::equal_to> - constexpr _Iter + [[nodiscard]] constexpr _Iter operator()(_Iter __first, _Sent __last, _Pred __pred = {}, _Proj __proj = {}) const { @@ -814,7 +815,7 @@ namespace ranges indirect_binary_predicate< projected<iterator_t<_Range>, _Proj>, projected<iterator_t<_Range>, _Proj>> _Pred = ranges::equal_to> - constexpr borrowed_iterator_t<_Range> + [[nodiscard]] constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, _Pred __pred = {}, _Proj __proj = {}) const { return (*this)(ranges::begin(__r), ranges::end(__r), diff --git a/libstdc++-v3/include/bits/regex_compiler.h b/libstdc++-v3/include/bits/regex_compiler.h index f24c7e3..21e7065 100644 --- a/libstdc++-v3/include/bits/regex_compiler.h +++ b/libstdc++-v3/include/bits/regex_compiler.h @@ -38,6 +38,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_END_NAMESPACE_CXX11 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr namespace __detail { /** @@ -221,9 +223,9 @@ namespace __detail _CharT _M_translate(_CharT __ch) const { - if _GLIBCXX17_CONSTEXPR (__icase) + if constexpr (__icase) return _M_traits.translate_nocase(__ch); - else if _GLIBCXX17_CONSTEXPR (__collate) + else if constexpr (__collate) return _M_traits.translate(__ch); else return __ch; @@ -285,7 +287,7 @@ namespace __detail bool _M_match_range(_CharT __first, _CharT __last, _CharT __ch) const { - if _GLIBCXX17_CONSTEXPR (!__icase) + if constexpr (!__icase) return __first <= __ch && __ch <= __last; else return this->_M_in_range_icase(__first, __last, __ch); @@ -376,26 +378,20 @@ namespace __detail bool operator()(_CharT __ch) const - { return _M_apply(__ch, typename is_same<_CharT, char>::type()); } - - bool - _M_apply(_CharT __ch, true_type) const { - auto __c = _M_translator._M_translate(__ch); - auto __n = _M_translator._M_translate('\n'); - auto __r = _M_translator._M_translate('\r'); - return __c != __n && __c != __r; - } - - bool - _M_apply(_CharT __ch, false_type) const - { - auto __c = _M_translator._M_translate(__ch); - auto __n = _M_translator._M_translate('\n'); - auto __r = _M_translator._M_translate('\r'); - auto __u2028 = _M_translator._M_translate(u'\u2028'); - auto __u2029 = _M_translator._M_translate(u'\u2029'); - return __c != __n && __c != __r && __c != __u2028 && __c != __u2029; + const auto __c = _M_translator._M_translate(__ch); + if (__c == _M_translator._M_translate('\n')) + return false; + if (__c == _M_translator._M_translate('\r')) + return false; + if constexpr (!is_same<_CharT, char>::value) + { + if (__c == _M_translator._M_translate(u'\u2028')) // line sep + return false; + if (__c == _M_translator._M_translate(u'\u2029')) // para sep + return false; + } + return true; } _TransT _M_translator; @@ -441,7 +437,10 @@ namespace __detail operator()(_CharT __ch) const { _GLIBCXX_DEBUG_ASSERT(_M_is_ready); - return _M_apply(__ch, _UseCache()); + if constexpr (_UseCache::value) + if (!(__ch & 0x80)) [[__likely__]] + return _M_cache[static_cast<_UnsignedCharT>(__ch)]; + return _M_apply(__ch); } void @@ -512,7 +511,9 @@ namespace __detail std::sort(_M_char_set.begin(), _M_char_set.end()); auto __end = std::unique(_M_char_set.begin(), _M_char_set.end()); _M_char_set.erase(__end, _M_char_set.end()); - _M_make_cache(_UseCache()); + if constexpr (_UseCache::value) + for (unsigned __i = 0; __i < 128; __i++) // Only cache 7-bit chars + _M_cache[__i] = _M_apply(static_cast<_CharT>(__i)); _GLIBCXX_DEBUG_ONLY(_M_is_ready = true); } @@ -531,22 +532,7 @@ namespace __detail using _UnsignedCharT = typename std::make_unsigned<_CharT>::type; bool - _M_apply(_CharT __ch, false_type) const; - - bool - _M_apply(_CharT __ch, true_type) const - { return _M_cache[static_cast<_UnsignedCharT>(__ch)]; } - - void - _M_make_cache(true_type) - { - for (unsigned __i = 0; __i < _M_cache.size(); __i++) - _M_cache[__i] = _M_apply(static_cast<_CharT>(__i), false_type()); - } - - void - _M_make_cache(false_type) - { } + _M_apply(_CharT __ch) const; private: _GLIBCXX_STD_C::vector<_CharT> _M_char_set; @@ -565,6 +551,7 @@ namespace __detail ///@} regex-detail } // namespace __detail +#pragma GCC diagnostic pop _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/bits/regex_compiler.tcc b/libstdc++-v3/include/bits/regex_compiler.tcc index cd0db27..59b79fd 100644 --- a/libstdc++-v3/include/bits/regex_compiler.tcc +++ b/libstdc++-v3/include/bits/regex_compiler.tcc @@ -598,7 +598,7 @@ namespace __detail template<typename _TraitsT, bool __icase, bool __collate> bool _BracketMatcher<_TraitsT, __icase, __collate>:: - _M_apply(_CharT __ch, false_type) const + _M_apply(_CharT __ch) const { return [this, __ch] { diff --git a/libstdc++-v3/include/bits/regex_executor.tcc b/libstdc++-v3/include/bits/regex_executor.tcc index e887e28..8f0f756 100644 --- a/libstdc++-v3/include/bits/regex_executor.tcc +++ b/libstdc++-v3/include/bits/regex_executor.tcc @@ -32,6 +32,8 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr namespace __detail { template<typename _BiIter, typename _Alloc, typename _TraitsT, @@ -217,7 +219,7 @@ namespace __detail } else // Non-greedy mode { - if (__dfs_mode) + if constexpr (__dfs_mode) { // vice-versa. _M_dfs(__match_mode, __state._M_next); @@ -322,7 +324,7 @@ namespace __detail if (_M_current == _M_end) return; - if (__dfs_mode) + if constexpr (__dfs_mode) { if (__state._M_matches(*_M_current)) { @@ -393,7 +395,7 @@ namespace __detail void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>:: _M_handle_backref(_Match_mode __match_mode, _StateIdT __i) { - __glibcxx_assert(__dfs_mode); + static_assert(__dfs_mode, "this should never be instantiated"); const auto& __state = _M_nfa[__i]; auto& __submatch = _M_cur_results[__state._M_backref_index]; @@ -426,7 +428,7 @@ namespace __detail void _Executor<_BiIter, _Alloc, _TraitsT, __dfs_mode>:: _M_handle_accept(_Match_mode __match_mode, _StateIdT) { - if _GLIBCXX17_CONSTEXPR (__dfs_mode) + if constexpr (__dfs_mode) { __glibcxx_assert(!_M_has_sol); if (__match_mode == _Match_mode::_Exact) @@ -529,7 +531,11 @@ namespace __detail case _S_opcode_match: _M_handle_match(__match_mode, __i); break; case _S_opcode_backref: - _M_handle_backref(__match_mode, __i); break; + if constexpr (__dfs_mode) + _M_handle_backref(__match_mode, __i); + else + __builtin_unreachable(); + break; case _S_opcode_accept: _M_handle_accept(__match_mode, __i); break; case _S_opcode_alternative: @@ -564,6 +570,7 @@ namespace __detail return __left_is_word != __right_is_word; } } // namespace __detail +#pragma GCC diagnostic pop _GLIBCXX_END_NAMESPACE_VERSION } // namespace 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/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h index a196a0f..f2b4601 100644 --- a/libstdc++-v3/include/bits/shared_ptr.h +++ b/libstdc++-v3/include/bits/shared_ptr.h @@ -909,6 +909,64 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public _Sp_owner_less<weak_ptr<_Tp>, shared_ptr<_Tp>> { }; +#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26 + + /** + * @brief Provides ownership-based hashing. + * @headerfile memory + * @since C++26 + */ + struct owner_hash + { + template<typename _Tp> + size_t + operator()(const shared_ptr<_Tp>& __s) const noexcept + { return __s.owner_hash(); } + + template<typename _Tp> + size_t + operator()(const weak_ptr<_Tp>& __s) const noexcept + { return __s.owner_hash(); } + + using is_transparent = void; + }; + + /** + * @brief Provides ownership-based mixed equality comparisons of + * shared and weak pointers. + * @headerfile memory + * @since C++26 + */ + struct owner_equal + { + template<typename _Tp1, typename _Tp2> + bool + operator()(const shared_ptr<_Tp1>& __lhs, + const shared_ptr<_Tp2>& __rhs) const noexcept + { return __lhs.owner_equal(__rhs); } + + template<typename _Tp1, typename _Tp2> + bool + operator()(const shared_ptr<_Tp1>& __lhs, + const weak_ptr<_Tp2>& __rhs) const noexcept + { return __lhs.owner_equal(__rhs); } + + template<typename _Tp1, typename _Tp2> + bool + operator()(const weak_ptr<_Tp1>& __lhs, + const shared_ptr<_Tp2>& __rhs) const noexcept + { return __lhs.owner_equal(__rhs); } + + template<typename _Tp1, typename _Tp2> + bool + operator()(const weak_ptr<_Tp1>& __lhs, + const weak_ptr<_Tp2>& __rhs) const noexcept + { return __lhs.owner_equal(__rhs); } + + using is_transparent = void; + }; +#endif + /** * @brief Base class allowing use of the member function `shared_from_this`. * @headerfile memory diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index 3622e02..b8c0d2e 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -148,7 +148,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Increment the use count (used when the count is greater than zero). void _M_add_ref_copy() - { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); } + { _S_chk(__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1)); } // Increment the use count if it is non-zero, throw otherwise. void @@ -200,7 +200,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Increment the weak count. void _M_weak_add_ref() noexcept - { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); } + { + // _M_weak_count can always use negative values because it cannot be + // observed by users (unlike _M_use_count). See _S_chk for details. + constexpr _Atomic_word __max = -1; + if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, 1) == __max) + [[__unlikely__]] __builtin_trap(); + } // Decrement the weak count. void @@ -224,19 +230,81 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION long _M_get_use_count() const noexcept { + // If long is wider than _Atomic_word then we can treat _Atomic_word + // as unsigned, and so double its usable range. If the widths are the + // same then casting to unsigned and then to long is a no-op. + using _Up = typename make_unsigned<_Atomic_word>::type; + // No memory barrier is used here so there is no synchronization // with other threads. - return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED); + return (_Up) __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED); } private: _Sp_counted_base(_Sp_counted_base const&) = delete; _Sp_counted_base& operator=(_Sp_counted_base const&) = delete; + // Called when incrementing _M_use_count to cause a trap on overflow. + // This should be passed the value of the counter before the increment. + static void + _S_chk(_Atomic_word __count) + { + // __max is the maximum allowed value for the shared reference count. + // All valid reference count values need to fit into [0,LONG_MAX) + // because users can observe the count via shared_ptr::use_count(). + // + // When long is wider than _Atomic_word, _M_use_count can go negative + // and the cast in _Sp_counted_base::use_count() will turn it into a + // positive value suitable for returning to users. The implementation + // only cares whether _M_use_count reaches zero after a decrement, + // so negative values are not a problem internally. + // So when possible, use -1 for __max (incrementing past that would + // overflow _M_use_count to 0, which means an empty shared_ptr). + // + // When long is not wider than _Atomic_word, __max is just the type's + // maximum positive value. We cannot use negative counts because they + // would not fit in [0,LONG_MAX) after casting to an unsigned type, + // which would cause use_count() to return bogus values. + constexpr _Atomic_word __max + = sizeof(long) > sizeof(_Atomic_word) + ? -1 : __gnu_cxx::__int_traits<_Atomic_word>::__max; + + if (__count == __max) [[__unlikely__]] + __builtin_trap(); + } + _Atomic_word _M_use_count; // #shared _Atomic_word _M_weak_count; // #weak + (#shared != 0) }; + // We use __atomic_add_single and __exchange_and_add_single in the _S_single + // member specializations because they use unsigned arithmetic and so avoid + // undefined overflow. + template<> + inline void + _Sp_counted_base<_S_single>::_M_add_ref_copy() + { + _S_chk(_M_use_count); + __gnu_cxx::__atomic_add_single(&_M_use_count, 1); + } + + template<> + inline void + _Sp_counted_base<_S_single>::_M_weak_release() noexcept + { + if (__gnu_cxx::__exchange_and_add_single(&_M_weak_count, -1) == 1) + _M_destroy(); + } + + template<> + inline long + _Sp_counted_base<_S_single>::_M_get_use_count() const noexcept + { + using _Up = typename make_unsigned<_Atomic_word>::type; + return (_Up) _M_use_count; + } + + template<> inline bool _Sp_counted_base<_S_single>:: @@ -244,7 +312,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (_M_use_count == 0) return false; - ++_M_use_count; + _M_add_ref_copy(); return true; } @@ -254,8 +322,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_add_ref_lock_nothrow() noexcept { __gnu_cxx::__scoped_lock sentry(*this); - if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0) + if (auto __c = __gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1)) + _S_chk(__c); + else { + // Count was zero, so we cannot lock it to get a shared_ptr. + // Reset to zero. This isn't racy, because there are no shared_ptr + // objects using this count and any other weak_ptr objects using it + // must call this function to modify _M_use_count, so would be + // synchronized by the mutex. _M_use_count = 0; return false; } @@ -279,23 +354,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED)); + _S_chk(__count); return true; } template<> inline void - _Sp_counted_base<_S_single>::_M_add_ref_copy() - { ++_M_use_count; } - - template<> - inline void _Sp_counted_base<_S_single>::_M_release() noexcept { - if (--_M_use_count == 0) + if (__gnu_cxx::__exchange_and_add_single(&_M_use_count, -1) == 1) { - _M_dispose(); - if (--_M_weak_count == 0) - _M_destroy(); + _M_dispose(); + _M_weak_release(); } } @@ -315,6 +385,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline void _Sp_counted_base<_S_atomic>::_M_release() noexcept { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count); #if ! _GLIBCXX_TSAN constexpr bool __lock_free @@ -325,7 +397,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // The ref-count members follow the vptr, so are aligned to // alignof(void*). constexpr bool __aligned = __alignof(long long) <= alignof(void*); - if _GLIBCXX17_CONSTEXPR (__lock_free && __double_word && __aligned) + if constexpr (__lock_free && __double_word && __aligned) { constexpr int __wordbits = __CHAR_BIT__ * sizeof(_Atomic_word); constexpr int __shiftbits = __double_word ? __wordbits : 0; @@ -359,27 +431,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { _M_release_last_use(); } +#pragma GCC diagnostic pop } - template<> - inline void - _Sp_counted_base<_S_single>::_M_weak_add_ref() noexcept - { ++_M_weak_count; } - - template<> - inline void - _Sp_counted_base<_S_single>::_M_weak_release() noexcept - { - if (--_M_weak_count == 0) - _M_destroy(); - } - - template<> - inline long - _Sp_counted_base<_S_single>::_M_get_use_count() const noexcept - { return _M_use_count; } - - // Forward declarations. template<typename _Tp, _Lock_policy _Lp = __default_lock_policy> class __shared_ptr; @@ -1119,6 +1173,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_less(const __weak_count<_Lp>& __rhs) const noexcept { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } +#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26 + size_t + _M_owner_hash() const noexcept + { return std::hash<_Sp_counted_base<_Lp>*>()(this->_M_pi); } +#endif + // Friend function injected into enclosing namespace and found by ADL friend inline bool operator==(const __shared_count& __a, const __shared_count& __b) noexcept @@ -1222,6 +1282,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_less(const __shared_count<_Lp>& __rhs) const noexcept { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } +#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26 + size_t + _M_owner_hash() const noexcept + { return std::hash<_Sp_counted_base<_Lp>*>()(this->_M_pi); } +#endif + // Friend function injected into enclosing namespace and found by ADL friend inline bool operator==(const __weak_count& __a, const __weak_count& __b) noexcept @@ -1712,6 +1778,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return _M_refcount._M_less(__rhs._M_refcount); } /// @} +#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26 + size_t owner_hash() const noexcept { return _M_refcount._M_owner_hash(); } + + template<typename _Tp1> + bool + owner_equal(__shared_ptr<_Tp1, _Lp> const& __rhs) const noexcept + { return _M_refcount == __rhs._M_refcount; } + + template<typename _Tp1> + bool + owner_equal(__weak_ptr<_Tp1, _Lp> const& __rhs) const noexcept + { return _M_refcount == __rhs._M_refcount; } +#endif + protected: // This constructor is non-standard, it is used by allocate_shared. template<typename _Alloc, typename... _Args> @@ -1983,6 +2063,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, _Lock_policy _Lp> class __weak_ptr { + public: + using element_type = typename remove_extent<_Tp>::type; + + private: template<typename _Yp, typename _Res = void> using _Compatible = typename enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type; @@ -1991,9 +2075,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Yp> using _Assignable = _Compatible<_Yp, __weak_ptr&>; - public: - using element_type = typename remove_extent<_Tp>::type; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + // Helper for construction/assignment: + template<typename _Yp> + static element_type* + _S_safe_upcast(const __weak_ptr<_Yp, _Lp>& __r) + { + // We know that _Yp and _Tp are compatible, that is, either + // _Yp* is convertible to _Tp* or _Yp is U[N] and _Tp is U cv []. + + // If _Yp is the same as _Tp after removing extents and cv + // qualifications, there's no pointer adjustments to do. This + // also allows us to support incomplete types. + using _At = typename remove_cv<typename remove_extent<_Tp>::type>::type; + using _Bt = typename remove_cv<typename remove_extent<_Yp>::type>::type; + if constexpr (is_same<_At, _Bt>::value) + return __r._M_ptr; + // If they're not the same type, but they're both scalars, + // we again don't need any adjustment. This allows us to support e.g. + // pointers to a differently cv qualified type X. + else if constexpr (__and_<is_scalar<_At>, is_scalar<_Bt>>::value) + return __r._M_ptr; +#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_is_virtual_base_of) + // If _Tp is not a virtual base class of _Yp, the pointer + // conversion does not require dereferencing __r._M_ptr; just + // rely on the implicit conversion. + else if constexpr (!__builtin_is_virtual_base_of(_Tp, _Yp)) + return __r._M_ptr; +#endif + // Expensive path; must lock() and do the pointer conversion while + // a shared_ptr keeps the pointee alive (because we may need + // to dereference). + else + return __r.lock().get(); + } +#pragma GCC diagnostic pop + public: constexpr __weak_ptr() noexcept : _M_ptr(nullptr), _M_refcount() { } @@ -2018,8 +2137,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // in multithreaded programs __r._M_ptr may be invalidated at any point. template<typename _Yp, typename = _Compatible<_Yp>> __weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept - : _M_refcount(__r._M_refcount) - { _M_ptr = __r.lock().get(); } + : _M_ptr(_S_safe_upcast(__r)), _M_refcount(__r._M_refcount) + { } template<typename _Yp, typename = _Compatible<_Yp>> __weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept @@ -2032,7 +2151,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Yp, typename = _Compatible<_Yp>> __weak_ptr(__weak_ptr<_Yp, _Lp>&& __r) noexcept - : _M_ptr(__r.lock().get()), _M_refcount(std::move(__r._M_refcount)) + : _M_ptr(_S_safe_upcast(__r)), _M_refcount(std::move(__r._M_refcount)) { __r._M_ptr = nullptr; } __weak_ptr& @@ -2042,7 +2161,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Assignable<_Yp> operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept { - _M_ptr = __r.lock().get(); + _M_ptr = _S_safe_upcast(__r); _M_refcount = __r._M_refcount; return *this; } @@ -2067,7 +2186,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Assignable<_Yp> operator=(__weak_ptr<_Yp, _Lp>&& __r) noexcept { - _M_ptr = __r.lock().get(); + _M_ptr = _S_safe_upcast(__r); _M_refcount = std::move(__r._M_refcount); __r._M_ptr = nullptr; return *this; @@ -2095,6 +2214,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION owner_before(const __weak_ptr<_Tp1, _Lp>& __rhs) const noexcept { return _M_refcount._M_less(__rhs._M_refcount); } +#ifdef __glibcxx_smart_ptr_owner_equality // >= C++26 + size_t owner_hash() const noexcept { return _M_refcount._M_owner_hash(); } + + template<typename _Tp1> + bool + owner_equal(const __shared_ptr<_Tp1, _Lp> & __rhs) const noexcept + { return _M_refcount == __rhs._M_refcount; } + + template<typename _Tp1> + bool + owner_equal(const __weak_ptr<_Tp1, _Lp> & __rhs) const noexcept + { return _M_refcount == __rhs._M_refcount; } +#endif + void reset() noexcept { __weak_ptr().swap(*this); } 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/std_function.h b/libstdc++-v3/include/bits/std_function.h index 1bf8b9a..3bfbe82 100644 --- a/libstdc++-v3/include/bits/std_function.h +++ b/libstdc++-v3/include/bits/std_function.h @@ -135,13 +135,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static _Functor* _M_get_pointer(const _Any_data& __source) noexcept { - if _GLIBCXX17_CONSTEXPR (__stored_locally) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + if constexpr (__stored_locally) { const _Functor& __f = __source._M_access<_Functor>(); return const_cast<_Functor*>(std::__addressof(__f)); } else // have stored a pointer return __source._M_access<_Functor*>(); +#pragma GCC diagnostic pop } private: @@ -312,21 +315,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return false; } }; - // Avoids instantiating ill-formed specializations of _Function_handler - // in std::function<_Signature>::target<_Functor>(). - // e.g. _Function_handler<Sig, void()> and _Function_handler<Sig, void> - // would be ill-formed. - template<typename _Signature, typename _Functor, - bool __valid = is_object<_Functor>::value> - struct _Target_handler - : _Function_handler<_Signature, typename remove_cv<_Functor>::type> - { }; - - template<typename _Signature, typename _Functor> - struct _Target_handler<_Signature, _Functor, false> - : _Function_handler<void, void> - { }; - /** * @brief Polymorphic function wrapper. * @ingroup functors @@ -644,13 +632,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const _Functor* target() const noexcept { - if _GLIBCXX17_CONSTEXPR (is_object<_Functor>::value) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + if constexpr (is_object<_Functor>::value) { - // For C++11 and C++14 if-constexpr is not used above, so - // _Target_handler avoids ill-formed _Function_handler types. - using _Handler = _Target_handler<_Res(_ArgTypes...), _Functor>; - - if (_M_manager == &_Handler::_M_manager + if (_M_manager == &_Handler<_Functor>::_M_manager #if __cpp_rtti || (_M_manager && typeid(_Functor) == target_type()) #endif @@ -661,6 +647,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __ptr._M_access<const _Functor*>(); } } +#pragma GCC diagnostic pop return nullptr; } /// @} diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index 71ead10..78c63e7 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -204,7 +204,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION while (__unary_pred(--__backTrack)) { if (--__remainder == 0) - return (__first - __count); // Success + return __first - _DistanceType(__count); // Success } __remainder = __count + 1 - (__first - __backTrack); } @@ -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) @@ -1259,9 +1258,12 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2) { if (__is_pod(_ValueType) && __k == 1) { + _RandomAccessIterator __mid = __p + _Distance(__n - 1); + _RandomAccessIterator __end = __mid; + ++__end; _ValueType __t = _GLIBCXX_MOVE(*__p); - _GLIBCXX_MOVE3(__p + 1, __p + __n, __p); - *(__p + __n - 1) = _GLIBCXX_MOVE(__t); + _GLIBCXX_MOVE3(__p + _Distance(1), __end, __p); + *__mid = _GLIBCXX_MOVE(__t); return __ret; } _RandomAccessIterator __q = __p + __k; @@ -1282,8 +1284,11 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2) __k = __n - __k; if (__is_pod(_ValueType) && __k == 1) { - _ValueType __t = _GLIBCXX_MOVE(*(__p + __n - 1)); - _GLIBCXX_MOVE_BACKWARD3(__p, __p + __n - 1, __p + __n); + _RandomAccessIterator __mid = __p + _Distance(__n - 1); + _RandomAccessIterator __end = __mid; + ++__end; + _ValueType __t = _GLIBCXX_MOVE(*__mid); + _GLIBCXX_MOVE_BACKWARD3(__p, __mid, __end); *__p = _GLIBCXX_MOVE(__t); return __ret; } @@ -1771,15 +1776,18 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) __insertion_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { - if (__first == __last) return; + if (__first == __last) + return; - for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + typedef iterator_traits<_RandomAccessIterator> _IterTraits; + typedef typename _IterTraits::difference_type _Dist; + + for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; ++__i) { if (__comp(__i, __first)) { - typename iterator_traits<_RandomAccessIterator>::value_type - __val = _GLIBCXX_MOVE(*__i); - _GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + 1); + typename _IterTraits::value_type __val = _GLIBCXX_MOVE(*__i); + _GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + _Dist(1)); *__first = _GLIBCXX_MOVE(__val); } else @@ -1813,10 +1821,13 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) __final_insertion_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { - if (__last - __first > int(_S_threshold)) + typename iterator_traits<_RandomAccessIterator>::difference_type + __threshold = _S_threshold; + + if (__last - __first > __threshold) { - std::__insertion_sort(__first, __first + int(_S_threshold), __comp); - std::__unguarded_insertion_sort(__first + int(_S_threshold), __last, + std::__insertion_sort(__first, __first + __threshold, __comp); + std::__unguarded_insertion_sort(__first + __threshold, __last, __comp); } else @@ -1852,10 +1863,14 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) __unguarded_partition_pivot(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { - _RandomAccessIterator __mid = __first + (__last - __first) / 2; - std::__move_median_to_first(__first, __first + 1, __mid, __last - 1, + typedef iterator_traits<_RandomAccessIterator> _IterTraits; + typedef typename _IterTraits::difference_type _Dist; + + _RandomAccessIterator __mid = __first + _Dist((__last - __first) / 2); + _RandomAccessIterator __second = __first + _Dist(1); + std::__move_median_to_first(__first, __second, __mid, __last - _Dist(1), __comp); - return std::__unguarded_partition(__first + 1, __last, __first, __comp); + return std::__unguarded_partition(__second, __last, __first, __comp); } template<typename _RandomAccessIterator, typename _Compare> @@ -1917,11 +1932,14 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2) _RandomAccessIterator __last, _Size __depth_limit, _Compare __comp) { + _RandomAccessIterator __after_nth = __nth; + ++__after_nth; + while (__last - __first > 3) { if (__depth_limit == 0) { - std::__heap_select(__first, __nth + 1, __last, __comp); + std::__heap_select(__first, __after_nth, __last, __comp); // Place the nth largest element in its final position. std::iter_swap(__first, __nth); return; @@ -2512,7 +2530,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)) @@ -3823,7 +3841,8 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO { if (__n2 <= 0) return __first; - auto __last = __first + __n2; + typename iterator_traits<_InputIterator>::difference_type __d = __n2; + auto __last = __first + __d; std::for_each(__first, __last, std::move(__f)); return __last; } @@ -4470,8 +4489,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 +4523,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 @@ -4544,6 +4564,9 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO if (__first == __last) return; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _Dist; + #if RAND_MAX < __INT_MAX__ if (__builtin_expect((__last - __first) >= RAND_MAX / 4, 0)) { @@ -4551,14 +4574,15 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO // instead of using rand() for all the random numbers needed. unsigned __xss = (unsigned)std::rand() ^ ((unsigned)std::rand() << 15); - for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; + ++__i) { __xss += !__xss; __xss ^= __xss << 13; __xss ^= __xss >> 17; __xss ^= __xss << 5; - _RandomAccessIterator __j = __first - + (__xss % ((__i - __first) + 1)); + _RandomAccessIterator __j + = __first + _Dist(__xss % ((__i - __first) + 1)); if (__i != __j) std::iter_swap(__i, __j); } @@ -4566,11 +4590,11 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } #endif - for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; ++__i) { // XXX rand() % N is not uniformly distributed - _RandomAccessIterator __j = __first - + (std::rand() % ((__i - __first) + 1)); + _RandomAccessIterator __j + = __first + _Dist(std::rand() % ((__i - __first) + 1)); if (__i != __j) std::iter_swap(__i, __j); } @@ -4611,9 +4635,14 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO if (__first == __last) return; - for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _Dist; + + for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; ++__i) { - _RandomAccessIterator __j = __first + __rand((__i - __first) + 1); + _RandomAccessIterator __j + = __first + _Dist(__rand((__i - __first) + 1)); if (__i != __j) std::iter_swap(__i, __j); } @@ -5024,7 +5053,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); @@ -5759,7 +5788,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO #if __cplusplus >= 201103L // N2722 + DR 915. template<typename _Tp> - _GLIBCXX14_CONSTEXPR + _GLIBCXX_NODISCARD _GLIBCXX14_CONSTEXPR inline _Tp min(initializer_list<_Tp> __l) { @@ -5769,7 +5798,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } template<typename _Tp, typename _Compare> - _GLIBCXX14_CONSTEXPR + _GLIBCXX_NODISCARD _GLIBCXX14_CONSTEXPR inline _Tp min(initializer_list<_Tp> __l, _Compare __comp) { @@ -5779,7 +5808,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } template<typename _Tp> - _GLIBCXX14_CONSTEXPR + _GLIBCXX_NODISCARD _GLIBCXX14_CONSTEXPR inline _Tp max(initializer_list<_Tp> __l) { @@ -5789,7 +5818,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } template<typename _Tp, typename _Compare> - _GLIBCXX14_CONSTEXPR + _GLIBCXX_NODISCARD _GLIBCXX14_CONSTEXPR inline _Tp max(initializer_list<_Tp> __l, _Compare __comp) { diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 119dbe9..820091a 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -1046,19 +1046,26 @@ _GLIBCXX_END_NAMESPACE_CONTAINER __size_to_integer(unsigned __GLIBCXX_TYPE_INT_N_2 __n) { return __n; } #endif #if defined(__GLIBCXX_TYPE_INT_N_3) - __extension__ inline _GLIBCXX_CONSTEXPR unsigned __GLIBCXX_TYPE_INT_N_3 - __size_to_integer(__GLIBCXX_TYPE_INT_N_3 __n) { return __n; } __extension__ inline _GLIBCXX_CONSTEXPR __GLIBCXX_TYPE_INT_N_3 + __size_to_integer(__GLIBCXX_TYPE_INT_N_3 __n) { return __n; } + __extension__ inline _GLIBCXX_CONSTEXPR unsigned __GLIBCXX_TYPE_INT_N_3 __size_to_integer(unsigned __GLIBCXX_TYPE_INT_N_3 __n) { return __n; } #endif +#if defined(__STRICT_ANSI__) && defined(__SIZEOF_INT128__) + __extension__ inline _GLIBCXX_CONSTEXPR __int128 + __size_to_integer(__int128 __n) { return __n; } + __extension__ inline _GLIBCXX_CONSTEXPR unsigned __int128 + __size_to_integer(unsigned __int128 __n) { return __n; } +#endif + inline _GLIBCXX_CONSTEXPR long long __size_to_integer(float __n) { return (long long)__n; } inline _GLIBCXX_CONSTEXPR long long __size_to_integer(double __n) { return (long long)__n; } inline _GLIBCXX_CONSTEXPR long long __size_to_integer(long double __n) { return (long long)__n; } -#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128) +#ifdef _GLIBCXX_USE_FLOAT128 __extension__ inline _GLIBCXX_CONSTEXPR long long __size_to_integer(__float128 __n) { return (long long)__n; } #endif @@ -1143,10 +1150,12 @@ _GLIBCXX_END_NAMESPACE_CONTAINER if (__n <= 0) return __first; - __glibcxx_requires_can_increment(__first, __n); + typename iterator_traits<_OutputIterator>::difference_type __d = __n; + __glibcxx_requires_can_increment(__first, __d); - std::__fill_a(__first, __first + __n, __value); - return __first + __n; + _OutputIterator __last = __first + __d; + std::__fill_a(__first, __last, __value); + return __last; } /** @@ -1303,11 +1312,11 @@ _GLIBCXX_END_NAMESPACE_CONTAINER __newlast1(_RAI1 __first1, _RAI1 __last1, _RAI2 __first2, _RAI2 __last2) { - const typename iterator_traits<_RAI1>::difference_type - __diff1 = __last1 - __first1; - const typename iterator_traits<_RAI2>::difference_type - __diff2 = __last2 - __first2; - return __diff2 < __diff1 ? __first1 + __diff2 : __last1; + typedef typename iterator_traits<_RAI1>::difference_type _Diff1; + typedef typename iterator_traits<_RAI2>::difference_type _Diff2; + const _Diff1 __diff1 = __last1 - __first1; + const _Diff2 __diff2 = __last2 - __first2; + return __diff2 < __diff1 ? __first1 + _Diff1(__diff2) : __last1; } template<typename _RAI> 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_heap.h b/libstdc++-v3/include/bits/stl_heap.h index 028ac83..f2b1e87 100644 --- a/libstdc++-v3/include/bits/stl_heap.h +++ b/libstdc++-v3/include/bits/stl_heap.h @@ -76,6 +76,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __is_heap_until(_RandomAccessIterator __first, _Distance __n, _Compare& __comp) { +#if __cplusplus >= 201103L + using _IterTraits = iterator_traits<_RandomAccessIterator>; + static_assert(is_same<typename _IterTraits::difference_type, + _Distance>::value, + "Argument 'n' must be the iterator's difference type"); +#endif _Distance __parent = 0; for (_Distance __child = 1; __child < __n; ++__child) { @@ -94,8 +100,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline bool __is_heap(_RandomAccessIterator __first, _Distance __n) { + typename iterator_traits<_RandomAccessIterator>::difference_type __d(__n); __gnu_cxx::__ops::_Iter_less_iter __comp; - return std::__is_heap_until(__first, __n, __comp) == __n; + return std::__is_heap_until(__first, __d, __comp) == __n; } template<typename _RandomAccessIterator, typename _Compare, @@ -104,9 +111,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline bool __is_heap(_RandomAccessIterator __first, _Compare __comp, _Distance __n) { + typename iterator_traits<_RandomAccessIterator>::difference_type __d(__n); typedef __decltype(__comp) _Cmp; __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp)); - return std::__is_heap_until(__first, __n, __cmp) == __n; + return std::__is_heap_until(__first, __d, __cmp) == __n; } template<typename _RandomAccessIterator> @@ -172,10 +180,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>) __glibcxx_requires_valid_range(__first, __last); __glibcxx_requires_irreflexive(__first, __last); - __glibcxx_requires_heap(__first, __last - 1); + __glibcxx_requires_heap(__first, __last - _DistanceType(1)); __gnu_cxx::__ops::_Iter_less_val __comp; - _ValueType __value = _GLIBCXX_MOVE(*(__last - 1)); + _ValueType __value = _GLIBCXX_MOVE(*(__last - _DistanceType(1))); std::__push_heap(__first, _DistanceType((__last - __first) - 1), _DistanceType(0), _GLIBCXX_MOVE(__value), __comp); } @@ -208,11 +216,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _RandomAccessIterator>) __glibcxx_requires_valid_range(__first, __last); __glibcxx_requires_irreflexive_pred(__first, __last, __comp); - __glibcxx_requires_heap_pred(__first, __last - 1, __comp); + __glibcxx_requires_heap_pred(__first, __last - _DistanceType(1), __comp); __decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp))) __cmp(_GLIBCXX_MOVE(__comp)); - _ValueType __value = _GLIBCXX_MOVE(*(__last - 1)); + _ValueType __value = _GLIBCXX_MOVE(*(__last - _DistanceType(1))); std::__push_heap(__first, _DistanceType((__last - __first) - 1), _DistanceType(0), _GLIBCXX_MOVE(__value), __cmp); } diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 9203a66..75e794f 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -1164,188 +1164,201 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const _Iterator& base() const _GLIBCXX_NOEXCEPT { return _M_current; } - }; - // Note: In what follows, the left- and right-hand-side iterators are - // allowed to vary in types (conceptually in cv-qualification) so that - // comparison between cv-qualified and non-cv-qualified iterators be - // valid. However, the greedy and unfriendly operators in std::rel_ops - // will make overload resolution ambiguous (when in scope) if we don't - // provide overloads whose operands are of the same type. Can someone - // remind me what generic programming is about? -- Gaby + private: + // Note: In what follows, the left- and right-hand-side iterators are + // allowed to vary in types (conceptually in cv-qualification) so that + // comparison between cv-qualified and non-cv-qualified iterators be + // valid. However, the greedy and unfriendly operators in std::rel_ops + // will make overload resolution ambiguous (when in scope) if we don't + // provide overloads whose operands are of the same type. Can someone + // remind me what generic programming is about? -- Gaby #ifdef __cpp_lib_three_way_comparison - template<typename _IteratorL, typename _IteratorR, typename _Container> - [[nodiscard, __gnu__::__always_inline__]] - constexpr bool - operator==(const __normal_iterator<_IteratorL, _Container>& __lhs, - const __normal_iterator<_IteratorR, _Container>& __rhs) - noexcept(noexcept(__lhs.base() == __rhs.base())) - requires requires { - { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>; - } - { return __lhs.base() == __rhs.base(); } - - template<typename _IteratorL, typename _IteratorR, typename _Container> - [[nodiscard, __gnu__::__always_inline__]] - constexpr std::__detail::__synth3way_t<_IteratorR, _IteratorL> - operator<=>(const __normal_iterator<_IteratorL, _Container>& __lhs, - const __normal_iterator<_IteratorR, _Container>& __rhs) - noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base()))) - { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); } + template<typename _Iter> + [[nodiscard, __gnu__::__always_inline__]] + friend + constexpr bool + operator==(const __normal_iterator& __lhs, + const __normal_iterator<_Iter, _Container>& __rhs) + noexcept(noexcept(__lhs.base() == __rhs.base())) + requires requires { + { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>; + } + { return __lhs.base() == __rhs.base(); } - template<typename _Iterator, typename _Container> - [[nodiscard, __gnu__::__always_inline__]] - constexpr bool - operator==(const __normal_iterator<_Iterator, _Container>& __lhs, - const __normal_iterator<_Iterator, _Container>& __rhs) - noexcept(noexcept(__lhs.base() == __rhs.base())) - requires requires { - { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>; - } - { return __lhs.base() == __rhs.base(); } + [[nodiscard, __gnu__::__always_inline__]] + friend + constexpr bool + operator==(const __normal_iterator& __lhs, const __normal_iterator& __rhs) + noexcept(noexcept(__lhs.base() == __rhs.base())) + requires requires { + { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>; + } + { return __lhs.base() == __rhs.base(); } - template<typename _Iterator, typename _Container> - [[nodiscard, __gnu__::__always_inline__]] - constexpr std::__detail::__synth3way_t<_Iterator> - operator<=>(const __normal_iterator<_Iterator, _Container>& __lhs, - const __normal_iterator<_Iterator, _Container>& __rhs) - noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base()))) - { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); } + template<typename _Iter> + [[nodiscard, __gnu__::__always_inline__]] + friend + constexpr std::__detail::__synth3way_t<_Iterator, _Iter> + operator<=>(const __normal_iterator& __lhs, + const __normal_iterator<_Iter, _Container>& __rhs) + noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base()))) + requires requires { + std::__detail::__synth3way(__lhs.base(), __rhs.base()); + } + { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); } #else - // Forward iterator requirements - template<typename _IteratorL, typename _IteratorR, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator==(const __normal_iterator<_IteratorL, _Container>& __lhs, - const __normal_iterator<_IteratorR, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() == __rhs.base(); } + // Forward iterator requirements + template<typename _Iter> + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + bool + operator==(const __normal_iterator& __lhs, + const __normal_iterator<_Iter, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() == __rhs.base(); } - template<typename _Iterator, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator==(const __normal_iterator<_Iterator, _Container>& __lhs, - const __normal_iterator<_Iterator, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() == __rhs.base(); } - - template<typename _IteratorL, typename _IteratorR, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator!=(const __normal_iterator<_IteratorL, _Container>& __lhs, - const __normal_iterator<_IteratorR, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() != __rhs.base(); } + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + bool + operator==(const __normal_iterator& __lhs, const __normal_iterator& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() == __rhs.base(); } - template<typename _Iterator, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator!=(const __normal_iterator<_Iterator, _Container>& __lhs, - const __normal_iterator<_Iterator, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() != __rhs.base(); } - - // Random access iterator requirements - template<typename _IteratorL, typename _IteratorR, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator<(const __normal_iterator<_IteratorL, _Container>& __lhs, - const __normal_iterator<_IteratorR, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() < __rhs.base(); } + template<typename _Iter> + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + bool + operator!=(const __normal_iterator& __lhs, + const __normal_iterator<_Iter, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() != __rhs.base(); } - template<typename _Iterator, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR - inline bool - operator<(const __normal_iterator<_Iterator, _Container>& __lhs, - const __normal_iterator<_Iterator, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() < __rhs.base(); } - - template<typename _IteratorL, typename _IteratorR, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator>(const __normal_iterator<_IteratorL, _Container>& __lhs, - const __normal_iterator<_IteratorR, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() > __rhs.base(); } + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + bool + operator!=(const __normal_iterator& __lhs, const __normal_iterator& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() != __rhs.base(); } - template<typename _Iterator, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator>(const __normal_iterator<_Iterator, _Container>& __lhs, - const __normal_iterator<_Iterator, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() > __rhs.base(); } - - template<typename _IteratorL, typename _IteratorR, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs, - const __normal_iterator<_IteratorR, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() <= __rhs.base(); } + // Random access iterator requirements + template<typename _Iter> + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + inline bool + operator<(const __normal_iterator& __lhs, + const __normal_iterator<_Iter, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() < __rhs.base(); } - template<typename _Iterator, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator<=(const __normal_iterator<_Iterator, _Container>& __lhs, - const __normal_iterator<_Iterator, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() <= __rhs.base(); } - - template<typename _IteratorL, typename _IteratorR, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs, - const __normal_iterator<_IteratorR, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() >= __rhs.base(); } + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX20_CONSTEXPR + bool + operator<(const __normal_iterator& __lhs, const __normal_iterator& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() < __rhs.base(); } - template<typename _Iterator, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline bool - operator>=(const __normal_iterator<_Iterator, _Container>& __lhs, - const __normal_iterator<_Iterator, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() >= __rhs.base(); } + template<typename _Iter> + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + bool + operator>(const __normal_iterator& __lhs, + const __normal_iterator<_Iter, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() > __rhs.base(); } + + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + bool + operator>(const __normal_iterator& __lhs, const __normal_iterator& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() > __rhs.base(); } + + template<typename _Iter> + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + bool + operator<=(const __normal_iterator& __lhs, + const __normal_iterator<_Iter, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() <= __rhs.base(); } + + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + bool + operator<=(const __normal_iterator& __lhs, const __normal_iterator& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() <= __rhs.base(); } + + template<typename _Iter> + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + bool + operator>=(const __normal_iterator& __lhs, + const __normal_iterator<_Iter, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() >= __rhs.base(); } + + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + bool + operator>=(const __normal_iterator& __lhs, const __normal_iterator& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() >= __rhs.base(); } #endif // three-way comparison - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // According to the resolution of DR179 not only the various comparison - // operators but also operator- must accept mixed iterator/const_iterator - // parameters. - template<typename _IteratorL, typename _IteratorR, typename _Container> + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 179. Comparison of const_iterators to iterators doesn't work + // According to the resolution of DR179 not only the various comparison + // operators but also operator- must accept mixed iterator/const_iterator + // parameters. + template<typename _Iter> #if __cplusplus >= 201103L - // DR 685. - [[__nodiscard__, __gnu__::__always_inline__]] - constexpr auto - operator-(const __normal_iterator<_IteratorL, _Container>& __lhs, - const __normal_iterator<_IteratorR, _Container>& __rhs) noexcept - -> decltype(__lhs.base() - __rhs.base()) + [[__nodiscard__, __gnu__::__always_inline__]] + friend + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 685. reverse_iterator/move_iterator difference has invalid signatures + constexpr auto + operator-(const __normal_iterator& __lhs, + const __normal_iterator<_Iter, _Container>& __rhs) noexcept + -> decltype(__lhs.base() - __rhs.base()) #else - inline typename __normal_iterator<_IteratorL, _Container>::difference_type - operator-(const __normal_iterator<_IteratorL, _Container>& __lhs, - const __normal_iterator<_IteratorR, _Container>& __rhs) + friend + difference_type + operator-(const __normal_iterator& __lhs, + const __normal_iterator<_Iter, _Container>& __rhs) #endif - { return __lhs.base() - __rhs.base(); } + { return __lhs.base() - __rhs.base(); } - template<typename _Iterator, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline typename __normal_iterator<_Iterator, _Container>::difference_type - operator-(const __normal_iterator<_Iterator, _Container>& __lhs, - const __normal_iterator<_Iterator, _Container>& __rhs) - _GLIBCXX_NOEXCEPT - { return __lhs.base() - __rhs.base(); } + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + difference_type + operator-(const __normal_iterator& __lhs, const __normal_iterator& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() - __rhs.base(); } - template<typename _Iterator, typename _Container> - _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR - inline __normal_iterator<_Iterator, _Container> - operator+(typename __normal_iterator<_Iterator, _Container>::difference_type - __n, const __normal_iterator<_Iterator, _Container>& __i) - _GLIBCXX_NOEXCEPT - { return __normal_iterator<_Iterator, _Container>(__i.base() + __n); } + _GLIBCXX_NODISCARD __attribute__((__always_inline__)) + friend + _GLIBCXX_CONSTEXPR + __normal_iterator + operator+(difference_type __n, const __normal_iterator& __i) + _GLIBCXX_NOEXCEPT + { return __normal_iterator(__i.base() + __n); } + }; _GLIBCXX_END_NAMESPACE_VERSION } // namespace __gnu_cxx @@ -2511,17 +2524,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION [[nodiscard]] friend constexpr iter_difference_t<_It2> operator-(const counted_iterator& __x, - const counted_iterator<_It2>& __y) + const counted_iterator<_It2>& __y) noexcept { return __y._M_length - __x._M_length; } [[nodiscard]] friend constexpr iter_difference_t<_It> - operator-(const counted_iterator& __x, default_sentinel_t) + operator-(const counted_iterator& __x, default_sentinel_t) noexcept { return -__x._M_length; } [[nodiscard]] friend constexpr iter_difference_t<_It> - operator-(default_sentinel_t, const counted_iterator& __y) + operator-(default_sentinel_t, const counted_iterator& __y) noexcept { return __y._M_length; } constexpr counted_iterator& @@ -2548,19 +2561,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION [[nodiscard]] friend constexpr bool operator==(const counted_iterator& __x, - const counted_iterator<_It2>& __y) + const counted_iterator<_It2>& __y) noexcept { return __x._M_length == __y._M_length; } [[nodiscard]] friend constexpr bool - operator==(const counted_iterator& __x, default_sentinel_t) + operator==(const counted_iterator& __x, default_sentinel_t) noexcept { return __x._M_length == 0; } template<common_with<_It> _It2> [[nodiscard]] friend constexpr strong_ordering operator<=>(const counted_iterator& __x, - const counted_iterator<_It2>& __y) + const counted_iterator<_It2>& __y) noexcept { return __y._M_length <=> __x._M_length; } [[nodiscard]] @@ -3086,8 +3099,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cpp_deduction_guides >= 201606 // These helper traits are used for deduction guides // of associative containers. + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4223. Deduction guides for maps are mishandling tuples and references template<typename _InputIterator> - using __iter_key_t = remove_const_t< + using __iter_key_t = __remove_cvref_t< #ifdef __glibcxx_tuple_like // >= C++23 tuple_element_t<0, typename iterator_traits<_InputIterator>::value_type>>; #else @@ -3095,11 +3111,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif template<typename _InputIterator> - using __iter_val_t + using __iter_val_t = __remove_cvref_t< #ifdef __glibcxx_tuple_like // >= C++23 - = tuple_element_t<1, typename iterator_traits<_InputIterator>::value_type>; + tuple_element_t<1, typename iterator_traits<_InputIterator>::value_type>>; #else - = typename iterator_traits<_InputIterator>::value_type::second_type; + typename iterator_traits<_InputIterator>::value_type::second_type>; #endif template<typename _T1, typename _T2> diff --git a/libstdc++-v3/include/bits/stl_iterator_base_funcs.h b/libstdc++-v3/include/bits/stl_iterator_base_funcs.h index 637159f..f78e535 100644 --- a/libstdc++-v3/include/bits/stl_iterator_base_funcs.h +++ b/libstdc++-v3/include/bits/stl_iterator_base_funcs.h @@ -130,6 +130,28 @@ _GLIBCXX_END_NAMESPACE_CONTAINER __distance(_OutputIterator, _OutputIterator, output_iterator_tag) = delete; #endif +#ifdef __glibcxx_concepts +namespace __detail +{ + // Satisfied if ITER_TRAITS(Iter)::iterator_category is valid and is + // at least as strong as ITER_TRAITS(Iter)::iterator_concept. + template<typename _Iter> + concept __iter_category_converts_to_concept + = convertible_to<typename __iter_traits<_Iter>::iterator_category, + typename __iter_traits<_Iter>::iterator_concept>; + + // Satisfied if the type is a C++20 iterator that defines iterator_concept, + // and its iterator_concept is stronger than its iterator_category (if any). + // Used by std::distance and std::advance to detect iterators which should + // dispatch based on their C++20 concept not their C++17 category. + template<typename _Iter> + concept __promotable_iterator + = input_iterator<_Iter> + && requires { typename __iter_traits<_Iter>::iterator_concept; } + && ! __iter_category_converts_to_concept<_Iter>; +} // namespace __detail +#endif + /** * @brief A generalization of pointer arithmetic. * @param __first An input iterator. @@ -149,6 +171,24 @@ _GLIBCXX_END_NAMESPACE_CONTAINER typename iterator_traits<_InputIterator>::difference_type distance(_InputIterator __first, _InputIterator __last) { +#ifdef __glibcxx_concepts + // A type which satisfies the C++20 random_access_iterator concept might + // have input_iterator_tag as its iterator_category type, which would + // mean we select the O(n) __distance. Or a C++20 std::input_iterator + // that is not a Cpp17InputIterator might have output_iterator_tag as + // its iterator_category type and then calling __distance with + // std::__iterator_category(__first) would be ill-formed. + // So for C++20 iterator types we can just choose to do the right thing. + if constexpr (__detail::__promotable_iterator<_InputIterator>) + { + if constexpr (random_access_iterator<_InputIterator>) + return __last - __first; + else + return std::__distance(std::move(__first), std::move(__last), + input_iterator_tag()); + } + else // assume it meets the Cpp17InputIterator requirements: +#endif // concept requirements -- taken care of in __distance return std::__distance(__first, __last, std::__iterator_category(__first)); @@ -221,9 +261,31 @@ _GLIBCXX_END_NAMESPACE_CONTAINER inline _GLIBCXX17_CONSTEXPR void advance(_InputIterator& __i, _Distance __n) { - // concept requirements -- taken care of in __advance - typename iterator_traits<_InputIterator>::difference_type __d = __n; - std::__advance(__i, __d, std::__iterator_category(__i)); +#ifdef __glibcxx_concepts + // A type which satisfies the C++20 bidirectional_iterator concept might + // have input_iterator_tag as its iterator_category type, which would + // mean we select the __advance overload which cannot move backwards. + // A C++20 random_access_iterator we might select the O(n) __advance + // if it doesn't meet the Cpp17RandomAccessIterator requirements. + // So for C++20 iterator types we can just choose to do the right thing. + if constexpr (__detail::__promotable_iterator<_InputIterator> + && ranges::__detail::__is_integer_like<_Distance>) + { + auto __d = static_cast<iter_difference_t<_InputIterator>>(__n); + if constexpr (random_access_iterator<_InputIterator>) + std::__advance(__i, __d, random_access_iterator_tag()); + else if constexpr (bidirectional_iterator<_InputIterator>) + std::__advance(__i, __d, bidirectional_iterator_tag()); + else + std::__advance(__i, __d, input_iterator_tag()); + } + else // assume it meets the Cpp17InputIterator requirements: +#endif + { + // concept requirements -- taken care of in __advance + typename iterator_traits<_InputIterator>::difference_type __d = __n; + std::__advance(__i, __d, std::__iterator_category(__i)); + } } #if __cplusplus >= 201103L diff --git a/libstdc++-v3/include/bits/stl_iterator_base_types.h b/libstdc++-v3/include/bits/stl_iterator_base_types.h index a67d7bd..0c34ad7 100644 --- a/libstdc++-v3/include/bits/stl_iterator_base_types.h +++ b/libstdc++-v3/include/bits/stl_iterator_base_types.h @@ -257,6 +257,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _InIter> concept __has_input_iter_cat = is_convertible_v<__iter_category_t<_InIter>, input_iterator_tag>; + +#ifdef __cpp_lib_concepts + // Is a Cpp17InputIterator or satisfies std::input_iterator. + template<typename _InIterator> + concept __any_input_iterator + = input_iterator<_InIterator> || __has_input_iter_cat<_InIterator>; +#endif #endif template<typename _It, diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h index 006ff46..68c23b8 100644 --- a/libstdc++-v3/include/bits/stl_map.h +++ b/libstdc++-v3/include/bits/stl_map.h @@ -1156,7 +1156,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ size_type erase(const key_type& __x) - { return _M_t.erase(__x); } + { return _M_t._M_erase_unique(__x); } #if __cplusplus >= 201103L // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 8c57712..231d0bb 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -445,7 +445,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Constructor accepting lvalues of `first_type` and `second_type` constexpr explicit(!_S_convertible<const _T1&, const _T2&>()) - pair(const _T1& __x, const _T2& __y) + pair(const type_identity_t<_T1>& __x, const _T2& __y) noexcept(_S_nothrow_constructible<const _T1&, const _T2&>()) requires (_S_constructible<const _T1&, const _T2&>()) : first(__x), second(__y) @@ -1132,6 +1132,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // C++23 #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2766. Swapping non-swappable types template<typename _T1, typename _T2> typename enable_if<!__and_<__is_swappable<_T1>, __is_swappable<_T2>>::value>::type @@ -1313,12 +1315,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Tp, typename _Up> constexpr _Tp&& get(pair<_Tp, _Up>&& __p) noexcept - { return std::move(__p.first); } + { return std::forward<_Tp>(__p.first); } template <typename _Tp, typename _Up> constexpr const _Tp&& get(const pair<_Tp, _Up>&& __p) noexcept - { return std::move(__p.first); } + { return std::forward<const _Tp>(__p.first); } template <typename _Tp, typename _Up> constexpr _Tp& @@ -1333,12 +1335,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Tp, typename _Up> constexpr _Tp&& get(pair<_Up, _Tp>&& __p) noexcept - { return std::move(__p.second); } + { return std::forward<_Tp>(__p.second); } template <typename _Tp, typename _Up> constexpr const _Tp&& get(const pair<_Up, _Tp>&& __p) noexcept - { return std::move(__p.second); } + { return std::forward<const _Tp>(__p.second); } #endif // __glibcxx_tuples_by_type diff --git a/libstdc++-v3/include/bits/stl_queue.h b/libstdc++-v3/include/bits/stl_queue.h index 554e076..a3a8bc1 100644 --- a/libstdc++-v3/include/bits/stl_queue.h +++ b/libstdc++-v3/include/bits/stl_queue.h @@ -70,6 +70,10 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION +#if __glibcxx_format_ranges + template<typename, typename> class formatter; +#endif + /** * @brief A standard container giving FIFO behavior. * @@ -369,6 +373,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION swap(c, __q.c); } #endif // __cplusplus >= 201103L + +#if __glibcxx_format_ranges + friend class formatter<queue<_Tp, _Sequence>, char>; + friend class formatter<queue<_Tp, _Sequence>, wchar_t>; +#endif }; #if __cpp_deduction_guides >= 201606 @@ -898,6 +907,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION swap(comp, __pq.comp); } #endif // __cplusplus >= 201103L + +#if __glibcxx_format_ranges + friend class formatter<priority_queue<_Tp, _Sequence, _Compare>, char>; + friend class formatter<priority_queue<_Tp, _Sequence, _Compare>, wchar_t>; +#endif }; #if __cpp_deduction_guides >= 201606 diff --git a/libstdc++-v3/include/bits/stl_set.h b/libstdc++-v3/include/bits/stl_set.h index 0799fd0..b65d631 100644 --- a/libstdc++-v3/include/bits/stl_set.h +++ b/libstdc++-v3/include/bits/stl_set.h @@ -728,7 +728,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ size_type erase(const key_type& __x) - { return _M_t.erase(__x); } + { return _M_t._M_erase_unique(__x); } #if __cplusplus >= 201103L // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/include/bits/stl_stack.h b/libstdc++-v3/include/bits/stl_stack.h index 7b32464..27c79d6 100644 --- a/libstdc++-v3/include/bits/stl_stack.h +++ b/libstdc++-v3/include/bits/stl_stack.h @@ -70,6 +70,10 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION +#if __glibcxx_format_ranges + template<typename, typename> class formatter; +#endif + /** * @brief A standard container giving FILO behavior. * @@ -343,6 +347,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION swap(c, __s.c); } #endif // __cplusplus >= 201103L + +#if __glibcxx_format_ranges + friend class formatter<stack<_Tp, _Sequence>, char>; + friend class formatter<stack<_Tp, _Sequence>, wchar_t>; +#endif }; #if __cpp_deduction_guides >= 201606 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_tree.h b/libstdc++-v3/include/bits/stl_tree.h index 6b35f99..4b7f482 100644 --- a/libstdc++-v3/include/bits/stl_tree.h +++ b/libstdc++-v3/include/bits/stl_tree.h @@ -1390,27 +1390,25 @@ namespace __rb_tree _M_end() const _GLIBCXX_NOEXCEPT { return this->_M_impl._M_header._M_base_ptr(); } - static const _Key& - _S_key(const _Node& __node) - { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2542. Missing const requirements for associative containers + template<typename _Key1, typename _Key2> + bool + _M_key_compare(const _Key1& __k1, const _Key2& __k2) const + { #if __cplusplus >= 201103L - // If we're asking for the key we're presumably using the comparison - // object, and so this is a good place to sanity check it. - static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{}, - "comparison object must be invocable " - "with two arguments of key type"); -# if __cplusplus >= 201703L - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 2542. Missing const requirements for associative containers - if constexpr (__is_invocable<_Compare&, const _Key&, const _Key&>{}) + // Enforce this here with a user-friendly message. static_assert( - is_invocable_v<const _Compare&, const _Key&, const _Key&>, - "comparison object must be invocable as const"); -# endif // C++17 -#endif // C++11 + __is_invocable<const _Compare&, const _Key&, const _Key&>::value, + "comparison object must be invocable with two arguments of key type" + ); +#endif + return _M_impl._M_key_compare(__k1, __k2); + } - return _KeyOfValue()(*__node._M_valptr()); - } + static const _Key& + _S_key(const _Node& __node) + { return _KeyOfValue()(*__node._M_valptr()); } static const _Key& _S_key(_Base_ptr __x) @@ -1852,6 +1850,9 @@ namespace __rb_tree size_type erase(const key_type& __x); + size_type + _M_erase_unique(const key_type& __x); + #if __cplusplus >= 201103L // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 130. Associative erase should return an iterator. @@ -1933,7 +1934,7 @@ namespace __rb_tree _M_find_tr(const _Kt& __k) const { const_iterator __j(_M_lower_bound_tr(__k)); - if (__j != end() && _M_impl._M_key_compare(__k, _S_key(__j._M_node))) + if (__j != end() && _M_key_compare(__k, _S_key(__j._M_node))) __j = end(); return __j; } @@ -1955,7 +1956,7 @@ namespace __rb_tree auto __x = _M_begin(); auto __y = _M_end(); while (__x) - if (!_M_impl._M_key_compare(_S_key(__x), __k)) + if (!_M_key_compare(_S_key(__x), __k)) { __y = __x; __x = _S_left(__x); @@ -1973,7 +1974,7 @@ namespace __rb_tree auto __x = _M_begin(); auto __y = _M_end(); while (__x) - if (_M_impl._M_key_compare(__k, _S_key(__x))) + if (_M_key_compare(__k, _S_key(__x))) { __y = __x; __x = _S_left(__x); @@ -2342,8 +2343,11 @@ namespace __rb_tree constexpr bool __move = !__move_if_noexcept_cond<value_type>::value; _Alloc_node __an(*this); _M_root() = _M_copy<__move>(__x, __an); - if _GLIBCXX17_CONSTEXPR (__move) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + if constexpr (__move) __x.clear(); +#pragma GCC diagnostic pop } } @@ -2474,8 +2478,8 @@ namespace __rb_tree _NodeGen& __node_gen) { bool __insert_left = (__x || __p == _M_end() - || _M_impl._M_key_compare(_KeyOfValue()(__v), - _S_key(__p))); + || _M_key_compare(_KeyOfValue()(__v), + _S_key(__p))); _Base_ptr __z = __node_gen(_GLIBCXX_FORWARD(_Arg, __v))->_M_base_ptr(); @@ -2500,8 +2504,8 @@ namespace __rb_tree #endif { bool __insert_left = (__p == _M_end() - || !_M_impl._M_key_compare(_S_key(__p), - _KeyOfValue()(__v))); + || !_M_key_compare(_S_key(__p), + _KeyOfValue()(__v))); _Base_ptr __z = _M_create_node(_GLIBCXX_FORWARD(_Arg, __v))->_M_base_ptr(); @@ -2529,7 +2533,7 @@ namespace __rb_tree while (__x) { __y = __x; - __x = !_M_impl._M_key_compare(_S_key(__x), _KeyOfValue()(__v)) ? + __x = !_M_key_compare(_S_key(__x), _KeyOfValue()(__v)) ? _S_left(__x) : _S_right(__x); } return _M_insert_lower(__y, _GLIBCXX_FORWARD(_Arg, __v)); @@ -2601,7 +2605,7 @@ namespace __rb_tree const _Key& __k) const { while (__x) - if (!_M_impl._M_key_compare(_S_key(__x), __k)) + if (!_M_key_compare(_S_key(__x), __k)) __y = __x, __x = _S_left(__x); else __x = _S_right(__x); @@ -2617,7 +2621,7 @@ namespace __rb_tree const _Key& __k) const { while (__x) - if (_M_impl._M_key_compare(__k, _S_key(__x))) + if (_M_key_compare(__k, _S_key(__x))) __y = __x, __x = _S_left(__x); else __x = _S_right(__x); @@ -2639,9 +2643,9 @@ namespace __rb_tree _Base_ptr __y = _M_end(); while (__x) { - if (_M_impl._M_key_compare(_S_key(__x), __k)) + if (_M_key_compare(_S_key(__x), __k)) __x = _S_right(__x); - else if (_M_impl._M_key_compare(__k, _S_key(__x))) + else if (_M_key_compare(__k, _S_key(__x))) __y = __x, __x = _S_left(__x); else { @@ -2671,9 +2675,9 @@ namespace __rb_tree _Base_ptr __y = _M_end(); while (__x) { - if (_M_impl._M_key_compare(_S_key(__x), __k)) + if (_M_key_compare(_S_key(__x), __k)) __x = _S_right(__x); - else if (_M_impl._M_key_compare(__k, _S_key(__x))) + else if (_M_key_compare(__k, _S_key(__x))) __y = __x, __x = _S_left(__x); else { @@ -2737,7 +2741,7 @@ namespace __rb_tree while (__x) { __y = __x; - __comp = _M_impl._M_key_compare(__k, _S_key(__x)); + __comp = _M_key_compare(__k, _S_key(__x)); __x = __comp ? _S_left(__x) : _S_right(__x); } iterator __j = iterator(__y); @@ -2748,7 +2752,7 @@ namespace __rb_tree else --__j; } - if (_M_impl._M_key_compare(_S_key(__j._M_node), __k)) + if (_M_key_compare(_S_key(__j._M_node), __k)) return _Res(__x, __y); return _Res(__j._M_node, _Base_ptr()); } @@ -2768,8 +2772,7 @@ namespace __rb_tree while (__x) { __y = __x; - __x = _M_impl._M_key_compare(__k, _S_key(__x)) ? - _S_left(__x) : _S_right(__x); + __x = _M_key_compare(__k, _S_key(__x)) ? _S_left(__x) : _S_right(__x); } return _Res(__x, __y); } @@ -2838,19 +2841,18 @@ namespace __rb_tree // end() if (__position._M_node == _M_end()) { - if (size() > 0 - && _M_impl._M_key_compare(_S_key(_M_rightmost()), __k)) + if (size() > 0 && _M_key_compare(_S_key(_M_rightmost()), __k)) return _Res(_Base_ptr(), _M_rightmost()); else return _M_get_insert_unique_pos(__k); } - else if (_M_impl._M_key_compare(__k, _S_key(__position._M_node))) + else if (_M_key_compare(__k, _S_key(__position._M_node))) { // First, try before... iterator __before(__position._M_node); if (__position._M_node == _M_leftmost()) // begin() return _Res(_M_leftmost(), _M_leftmost()); - else if (_M_impl._M_key_compare(_S_key((--__before)._M_node), __k)) + else if (_M_key_compare(_S_key((--__before)._M_node), __k)) { if (!_S_right(__before._M_node)) return _Res(_Base_ptr(), __before._M_node); @@ -2860,13 +2862,13 @@ namespace __rb_tree else return _M_get_insert_unique_pos(__k); } - else if (_M_impl._M_key_compare(_S_key(__position._M_node), __k)) + else if (_M_key_compare(_S_key(__position._M_node), __k)) { // ... then try after. iterator __after(__position._M_node); if (__position._M_node == _M_rightmost()) return _Res(_Base_ptr(), _M_rightmost()); - else if (_M_impl._M_key_compare(__k, _S_key((++__after)._M_node))) + else if (_M_key_compare(__k, _S_key((++__after)._M_node))) { if (!_S_right(__position._M_node)) return _Res(_Base_ptr(), __position._M_node); @@ -2923,18 +2925,18 @@ namespace __rb_tree if (__position._M_node == _M_end()) { if (size() > 0 - && !_M_impl._M_key_compare(__k, _S_key(_M_rightmost()))) + && !_M_key_compare(__k, _S_key(_M_rightmost()))) return _Res(_Base_ptr(), _M_rightmost()); else return _M_get_insert_equal_pos(__k); } - else if (!_M_impl._M_key_compare(_S_key(__position._M_node), __k)) + else if (!_M_key_compare(_S_key(__position._M_node), __k)) { // First, try before... iterator __before(__position._M_node); if (__position._M_node == _M_leftmost()) // begin() return _Res(_M_leftmost(), _M_leftmost()); - else if (!_M_impl._M_key_compare(__k, _S_key((--__before)._M_node))) + else if (!_M_key_compare(__k, _S_key((--__before)._M_node))) { if (!_S_right(__before._M_node)) return _Res(_Base_ptr(), __before._M_node); @@ -2950,7 +2952,7 @@ namespace __rb_tree iterator __after(__position._M_node); if (__position._M_node == _M_rightmost()) return _Res(_Base_ptr(), _M_rightmost()); - else if (!_M_impl._M_key_compare(_S_key((++__after)._M_node), __k)) + else if (!_M_key_compare(_S_key((++__after)._M_node), __k)) { if (!_S_right(__position._M_node)) return _Res(_Base_ptr(), __position._M_node); @@ -2999,8 +3001,7 @@ namespace __rb_tree -> iterator { bool __insert_left = (__x || __p == _M_end() - || _M_impl._M_key_compare(_S_key(__z), - _S_key(__p))); + || _M_key_compare(_S_key(__z), _S_key(__p))); _Base_ptr __base_z = __z->_M_base_ptr(); _Node_traits::_S_insert_and_rebalance @@ -3017,8 +3018,7 @@ namespace __rb_tree -> iterator { bool __insert_left = (__p == _M_end() - || !_M_impl._M_key_compare(_S_key(__p), - _S_key(__z))); + || !_M_key_compare(_S_key(__p), _S_key(__z))); _Base_ptr __base_z = __z->_M_base_ptr(); _Node_traits::_S_insert_and_rebalance @@ -3039,7 +3039,7 @@ namespace __rb_tree while (__x) { __y = __x; - __x = !_M_impl._M_key_compare(_S_key(__x), _S_key(__z)) ? + __x = !_M_key_compare(_S_key(__x), _S_key(__z)) ? _S_left(__x) : _S_right(__x); } return _M_insert_lower_node(__y, __z); @@ -3144,6 +3144,20 @@ namespace __rb_tree template<typename _Key, typename _Val, typename _KeyOfValue, typename _Compare, typename _Alloc> + typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::size_type + _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: + _M_erase_unique(const _Key& __x) + { + iterator __it = find(__x); + if (__it == end()) + return 0; + + _M_erase_aux(__it); + return 1; + } + + template<typename _Key, typename _Val, typename _KeyOfValue, + typename _Compare, typename _Alloc> typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: @@ -3151,8 +3165,7 @@ namespace __rb_tree { iterator __j(_M_lower_bound(_M_begin(), _M_end(), __k)); return (__j == end() - || _M_impl._M_key_compare(__k, - _S_key(__j._M_node))) ? end() : __j; + || _M_key_compare(__k, _S_key(__j._M_node))) ? end() : __j; } template<typename _Key, typename _Val, typename _KeyOfValue, @@ -3164,8 +3177,7 @@ namespace __rb_tree { const_iterator __j(_M_lower_bound(_M_begin(), _M_end(), __k)); return (__j == end() - || _M_impl._M_key_compare(__k, - _S_key(__j._M_node))) ? end() : __j; + || _M_key_compare(__k, _S_key(__j._M_node))) ? end() : __j; } template<typename _Key, typename _Val, typename _KeyOfValue, @@ -3205,9 +3217,9 @@ namespace __rb_tree || (__R && __R->_M_color == _S_red)) return false; - if (__L && _M_impl._M_key_compare(_S_key(__x), _S_key(__L))) + if (__L && _M_key_compare(_S_key(__x), _S_key(__L))) return false; - if (__R && _M_impl._M_key_compare(_S_key(__R), _S_key(__x))) + if (__R && _M_key_compare(_S_key(__R), _S_key(__x))) return false; if (!__L && !__R && _Rb_tree_black_count(__x, _M_root()) != __len) diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h index b1428db..351c3a1 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. @@ -357,7 +377,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::__niter_base(__last), __x); else - std::__do_uninit_copy(__first, __last, __x); + std::__do_uninit_fill(__first, __last, __x); } // Overload for pointers. @@ -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); @@ -902,11 +922,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // __uninitialized_default // Fills [first, last) with value-initialized value_types. template<typename _ForwardIterator> - _GLIBCXX26_CONSTEXPR + _GLIBCXX20_CONSTEXPR inline void __uninitialized_default(_ForwardIterator __first, _ForwardIterator __last) { +#ifdef __cpp_lib_is_constant_evaluated + if (std::is_constant_evaluated()) + return __uninitialized_default_1<false>:: + __uninit_default(__first, __last); +#endif + typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; // trivial types can have deleted assignment @@ -955,7 +981,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 +1006,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 +1033,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 +1059,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 +1115,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 +1138,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 +1302,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 +1334,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 aff9d5d..7625333 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: @@ -518,29 +520,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return _S_nothrow_relocate(__is_move_insertable<_Tp_alloc_type>{}); } - static pointer - _S_do_relocate(pointer __first, pointer __last, pointer __result, - _Tp_alloc_type& __alloc, true_type) noexcept - { - return std::__relocate_a(__first, __last, __result, __alloc); - } - - static pointer - _S_do_relocate(pointer, pointer, pointer __result, - _Tp_alloc_type&, false_type) noexcept - { return __result; } - static _GLIBCXX20_CONSTEXPR pointer _S_relocate(pointer __first, pointer __last, pointer __result, _Tp_alloc_type& __alloc) noexcept { -#if __cpp_if_constexpr - // All callers have already checked _S_use_relocate() so just do it. - return std::__relocate_a(__first, __last, __result, __alloc); -#else - using __do_it = __bool_constant<_S_use_relocate()>; - return _S_do_relocate(__first, __last, __result, __alloc, __do_it{}); -#endif +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + if constexpr (_S_use_relocate()) + return std::__relocate_a(__first, __last, __result, __alloc); + else + return __result; +#pragma GCC diagnostic pop } #endif // C++11 @@ -1118,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); } @@ -1164,7 +1154,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER resize(size_type __new_size, const value_type& __x) { if (__new_size > size()) - _M_fill_insert(end(), __new_size - size(), __x); + _M_fill_append(__new_size - size(), __x); else if (__new_size < size()) _M_erase_at_end(this->_M_impl._M_start + __new_size); } @@ -1185,7 +1175,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER resize(size_type __new_size, value_type __x = value_type()) { if (__new_size > size()) - _M_fill_insert(end(), __new_size - size(), __x); + _M_fill_append(__new_size - size(), __x); else if (__new_size < size()) _M_erase_at_end(this->_M_impl._M_start + __new_size); } @@ -1210,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); } @@ -1981,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, @@ -2097,6 +2088,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER void _M_fill_insert(iterator __pos, size_type __n, const value_type& __x); + // Called by resize(n,x), and the _M_fill_insert(end(), n, x) + _GLIBCXX20_CONSTEXPR + void + _M_fill_append(size_type __n, const value_type& __x); + #if __cplusplus >= 201103L // Called by resize(n). _GLIBCXX20_CONSTEXPR diff --git a/libstdc++-v3/include/bits/unicode.h b/libstdc++-v3/include/bits/unicode.h index f1b6bf4..88e97d4 100644 --- a/libstdc++-v3/include/bits/unicode.h +++ b/libstdc++-v3/include/bits/unicode.h @@ -86,6 +86,25 @@ namespace __unicode { return *__it == iter_value_t<_It>{}; } }; + // An iterator over an input range of FromFmt code units that yields either + // UTF-8, UTF-16, or UTF-32, as a range of ToFmt code units. + // The code units from the input range are interpreted as Unicode code points + // and the iterator produces the individual code unit for each code point. + // Invalid sequences in the input are replaced with U+FFDD so that the result + // is always valid UTF-8, UTF-16, or UTF-32. + // + // The iterator knows the bounds of the underlying input range and will not + // read outside those bounds (incrementing or decrementing at the boundary + // is erroneously idempotent). + // + // On construction, the iterator attemps to decode a single code point from + // the input range and then encode it into an internal buffer in the output + // format, e.g. if the input is UTF-8 and the output is UTF-16, it might read + // three char8_t code units from the input and store two char16_t code units + // in its buffer. Incrementing the iterator will first iterate over buffer, + // yielding each code unit in turn, and then extract another code point from + // the input. Failure to extract a valid code point from the input will store + // U+FFFD in the buffer, encoded as the appropriate code units of type ToFmt. template<typename _FromFmt, typename _ToFmt, input_iterator _Iter, sentinel_for<_Iter> _Sent = _Iter, typename _ErrorHandler = _Repl> @@ -162,17 +181,20 @@ namespace __unicode constexpr _Utf_iterator& operator++() { - if (_M_buf_index + 1 == _M_buf_last && _M_curr() != _M_last) + if (_M_buf_index + 1 < _M_buf_last) + ++_M_buf_index; // Move to the next code unit in the buffer. + else if (_M_curr() != _M_last) { + // Advance past the current code point (for non-forward iterators + // we already moved there after decoding the last code point). if constexpr (forward_iterator<_Iter>) std::advance(_M_curr(), _M_to_increment); if (_M_curr() == _M_last) _M_buf_index = 0; - else + else // Decode next code point from the input and update buffer. _M_read(); } - else if (_M_buf_index + 1 < _M_buf_last) - ++_M_buf_index; + // else erroneous, but ignored for now. return *this; } @@ -187,10 +209,15 @@ namespace __unicode constexpr _Utf_iterator& operator--() requires bidirectional_iterator<_Iter> { - if (!_M_buf_index && _M_curr() != _M_first()) - _M_read_reverse(); - else if (_M_buf_index) + if (_M_buf_index > 0) --_M_buf_index; + else if (_M_curr() != _M_first()) + { + _M_read_reverse(); + _M_buf_index = _M_buf_last - 1; + ranges::advance(_M_curr(), -_M_to_increment); + } + // else erroneous, but ignored for now. return *this; } @@ -247,7 +274,18 @@ namespace __unicode } constexpr void - _M_read_reverse(); // TODO + _M_read_reverse() requires bidirectional_iterator<_Iter> + { + if constexpr (sizeof(_FromFmt) == sizeof(uint8_t)) + _M_read_reverse_utf8(); + else if constexpr (sizeof(_FromFmt) == sizeof(uint16_t)) + _M_read_reverse_utf16(); + else + { + static_assert(sizeof(_FromFmt) == sizeof(uint32_t)); + _M_read_reverse_utf32(); + } + } template<typename> struct _Guard @@ -263,7 +301,7 @@ namespace __unicode _It _M_orig; }; - constexpr void + constexpr char32_t _M_read_utf8() { _Guard<_Iter> __g{this, _M_curr()}; @@ -361,6 +399,8 @@ namespace __unicode __c = _S_error(); _M_update(__c, __to_incr); + + return __c; } constexpr void @@ -403,6 +443,116 @@ namespace __unicode _M_update(__c, 1); } + constexpr void + _M_read_reverse_utf8() requires bidirectional_iterator<_Iter> + { + const auto __first = _M_first(); + auto __curr = _M_curr(); + // The code point we decode: + char32_t __c{}; + // The last code unit read: + uint8_t __u = *--__curr; + // Count of bytes read: + uint8_t __to_incr = 1; + + if (__u <= 0x7F) [[likely]] + { + _M_update(__u, 1); + return; + } + + // Continuation bytes match 10xxxxxx + auto __is_continuation = [](uint8_t __b) { + return (__b & 0xC0) == 0x80; + }; + // 0xC0 and 0xC1 would produce overlong encodings of ASCII characters. + // 0xF5-0xFF would produce code points above U+10FFFF + auto __is_invalid = [](uint8_t __b) { + return (__b & 0xFE) == 0xC0 || __b >= 0xF5; + }; + + // No valid or invalid multibyte sequence is longer than 4 bytes, + // so skip back over at most four bytes. + while (__is_continuation(__u) && __to_incr < 4 && __curr != __first) + { + ++__to_incr; + __u = *--__curr; + } + + // If the last byte read was a continuation byte then either we read + // four continuation bytes, or stopped at the start of the sequence. + // Either way, the maximal subparts are the individual continuation + // bytes so each one should be replaced with U+FFFD. + if (__is_continuation(__u) || __is_invalid(__u)) [[unlikely]] + { + // Either found four continuation bytes (maximum allowed is three) + // or first non-continuation byte is an invalid UTF-8 code unit. + _M_update(_S_error(), 1); + return; + } + // __u is a valid start byte so use countl_one to get the expected + // length of the multibyte sequence that starts with this byte. + int __seq_length = std::countl_one((unsigned char)__u); + if (__seq_length < __to_incr) [[unlikely]] + { + // If the expected number of continuation bytes is less than + // the number we found, then the last continuation byte is a + // maximal subpart and the decremented iterator points to it. + _M_update(_S_error(), 1); + return; + } + + auto __orig = std::__exchange(_M_curr(), std::move(__curr)); + if (_M_read_utf8() == _S_error()) [[unlikely]] + { + if (_M_to_increment < __to_incr) // Read truncated sequence, set + _M_to_increment = 1; // curr to last continuation byte. + } + + _M_curr() = std::move(__orig); + // operator--() will move back by _M_to_increment + } + + constexpr void + _M_read_reverse_utf16() requires bidirectional_iterator<_Iter> + { + _Guard<_Iter> __g{this, _M_curr()}; + char32_t __c{}; + uint16_t __u = *--_M_curr(); + uint8_t __to_incr = 1; + + if (__u < 0xD800 || __u > 0xDFFF) [[likely]] + __c = __u; + else if (__u >= 0xDC00 && _M_curr() != _M_first()) [[likely]] + { + // read a low surrogate, expect a high surrogate before it. + uint16_t __u2 = *--_M_curr(); + if (__u2 < 0xD800 || __u2 > 0xDC00) [[unlikely]] + __c = _S_error(); // unpaired low surrogate + else + { + __to_incr = 2; + uint32_t __x = (__u2 & 0x3F) << 10 | (__u & 0x3FF); + uint32_t __w = (__u2 >> 6) & 0x1F; + __c = (__w + 1) << 16 | __x; + } + } + else + __c = _S_error(); // unpaired surrogate + + _M_update(__c, __to_incr); + } + + constexpr void + _M_read_reverse_utf32() requires bidirectional_iterator<_Iter> + { + _Guard<_Iter> __g{this, _M_curr()}; + char32_t __c = *--_M_curr(); + if (!__is_scalar_value(__c)) [[unlikely]] + __c = _S_error(); + _M_update(__c, 1); + } + // Encode the code point __c as one or more code units in _M_buf. constexpr void _M_update(char32_t __c, uint8_t __to_incr) @@ -487,8 +637,7 @@ namespace __unicode constexpr _Iter _M_curr() const { return _M_first_and_curr._M_curr; } - array<value_type, 4 / sizeof(_ToFmt)> _M_buf; - + // _M_first is not needed for non-bidirectional ranges. template<typename _It> struct _First_and_curr { @@ -502,6 +651,8 @@ namespace __unicode _First_and_curr(const _First_and_curr<_It2>& __other) : _M_curr(__other._M_curr) { } + // First code unit of the current code point for forward iterators, + // past-the-end of the current code point for input iterators. _It _M_curr; }; @@ -519,18 +670,24 @@ namespace __unicode _First_and_curr(const _First_and_curr<_It2>& __other) : _M_first(__other._M_first), _M_curr(__other._M_curr) { } - _It _M_first; - _It _M_curr; + _It _M_first; // Start of the underlying range. + _It _M_curr; // First code unit of the current code point. }; + // Iterators pointing to the start of the underlying range and to the + // start (or end, for non-forward iterators) of the current code point. _First_and_curr<_Iter> _M_first_and_curr; - uint8_t _M_buf_index = 0; - uint8_t _M_buf_last = 0; - uint8_t _M_to_increment = 0; - + // The end of the underlying input range. [[no_unique_address]] _Sent _M_last; + // Buffer holding the individual code units of the current code point. + array<value_type, 4 / sizeof(_ToFmt)> _M_buf; + + uint8_t _M_buf_index = 0; // Index of current code unit in the buffer. + uint8_t _M_buf_last = 0; // Number of code units in the buffer. + uint8_t _M_to_increment = 0; // How far to advance _M_curr on increment. + template<typename _FromFmt2, typename _ToFmt2, input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, typename _ErrHandler> diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h index d96dcbd..77b1e96 100644 --- a/libstdc++-v3/include/bits/uniform_int_dist.h +++ b/libstdc++-v3/include/bits/uniform_int_dist.h @@ -308,9 +308,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const __uctype __uerange = __urange + 1; // __urange can be zero +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr #if defined __UINT64_TYPE__ && defined __UINT32_TYPE__ #if __SIZEOF_INT128__ - if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT64_MAX__) + if constexpr (__urngrange == __UINT64_MAX__) { // __urng produces values that use exactly 64-bits, // so use 128-bit integers to downscale to desired range. @@ -320,7 +322,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } else #endif - if _GLIBCXX17_CONSTEXPR (__urngrange == __UINT32_MAX__) + if constexpr (__urngrange == __UINT32_MAX__) { // __urng produces values that use exactly 32-bits, // so use 64-bit integers to downscale to desired range. @@ -338,6 +340,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION while (__ret >= __past); __ret /= __scaling; } +#pragma GCC diagnostic pop } else if (__urngrange < __urange) { diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index 6ae46a9..978deb3 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -1,4 +1,3 @@ - // unique_ptr implementation -*- C++ -*- // Copyright (C) 2008-2025 Free Software Foundation, Inc. @@ -832,6 +831,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __x.swap(__y); } #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2766. Swapping non-swappable types template<typename _Tp, typename _Dp> typename enable_if<!__is_swappable<_Dp>::value>::type swap(unique_ptr<_Tp, _Dp>&, diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h index 5bc58e8..cc9e2c4 100644 --- a/libstdc++-v3/include/bits/unordered_map.h +++ b/libstdc++-v3/include/bits/unordered_map.h @@ -91,9 +91,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * * @tparam _Key Type of key objects. * @tparam _Tp Type of mapped objects. - * @tparam _Hash Hashing function object type, defaults to hash<_Value>. + * @tparam _Hash Hashing function object type, defaults to hash<_Key>. * @tparam _Pred Predicate function object type, defaults - * to equal_to<_Value>. + * to equal_to<_Key>. * @tparam _Alloc Allocator type, defaults to * std::allocator<std::pair<const _Key, _Tp>>. * @@ -251,6 +251,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : unordered_map(__n, __hf, key_equal(), __a) { } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered containers + template<typename _InputIterator> + unordered_map(_InputIterator __first, _InputIterator __last, + const allocator_type& __a) + : unordered_map(__first, __last, 0, hasher(), key_equal(), __a) + { } + template<typename _InputIterator> unordered_map(_InputIterator __first, _InputIterator __last, size_type __n, @@ -271,6 +279,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : unordered_map(__l, __n, hasher(), key_equal(), __a) { } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered containers + unordered_map(initializer_list<value_type> __l, + const allocator_type& __a) + : unordered_map(__l, 0, hasher(), key_equal(), __a) + { } + unordered_map(initializer_list<value_type> __l, size_type __n, const hasher& __hf, const allocator_type& __a) @@ -1345,9 +1360,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * * @tparam _Key Type of key objects. * @tparam _Tp Type of mapped objects. - * @tparam _Hash Hashing function object type, defaults to hash<_Value>. + * @tparam _Hash Hashing function object type, defaults to hash<_Key>. * @tparam _Pred Predicate function object type, defaults - * to equal_to<_Value>. + * to equal_to<_Key>. * @tparam _Alloc Allocator type, defaults to * std::allocator<std::pair<const _Key, _Tp>>. * @@ -1504,6 +1519,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : unordered_multimap(__n, __hf, key_equal(), __a) { } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered containers + template<typename _InputIterator> + unordered_multimap(_InputIterator __first, _InputIterator __last, + const allocator_type& __a) + : unordered_multimap(__first, __last, 0, hasher(), key_equal(), __a) + { } + template<typename _InputIterator> unordered_multimap(_InputIterator __first, _InputIterator __last, size_type __n, @@ -1518,6 +1541,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : unordered_multimap(__first, __last, __n, __hf, key_equal(), __a) { } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered containers + unordered_multimap(initializer_list<value_type> __l, + const allocator_type& __a) + : unordered_multimap(__l, 0, hasher(), key_equal(), __a) + { } + unordered_multimap(initializer_list<value_type> __l, size_type __n, const allocator_type& __a) diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h index 091bae6..5649dd7 100644 --- a/libstdc++-v3/include/bits/unordered_set.h +++ b/libstdc++-v3/include/bits/unordered_set.h @@ -245,6 +245,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : unordered_set(__n, __hf, key_equal(), __a) { } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered container + template<typename _InputIterator> + unordered_set(_InputIterator __first, _InputIterator __last, + const allocator_type& __a) + : unordered_set(__first, __last, 0, hasher(), key_equal(), __a) + { } + template<typename _InputIterator> unordered_set(_InputIterator __first, _InputIterator __last, size_type __n, @@ -259,6 +267,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : unordered_set(__first, __last, __n, __hf, key_equal(), __a) { } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered container + unordered_set(initializer_list<value_type> __l, + const allocator_type& __a) + : unordered_set(__l, 0, hasher(), key_equal(), __a) + { } + unordered_set(initializer_list<value_type> __l, size_type __n, const allocator_type& __a) @@ -987,6 +1003,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typename iterator_traits<_InputIterator>::value_type>, _Allocator>; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered container + template<typename _InputIterator, typename _Allocator, + typename = _RequireInputIter<_InputIterator>, + typename = _RequireAllocator<_Allocator>> + unordered_set(_InputIterator, _InputIterator, _Allocator) + -> unordered_set<typename iterator_traits<_InputIterator>::value_type, + hash< + typename iterator_traits<_InputIterator>::value_type>, + equal_to< + typename iterator_traits<_InputIterator>::value_type>, + _Allocator>; + template<typename _InputIterator, typename _Hash, typename _Allocator, typename = _RequireInputIter<_InputIterator>, typename = _RequireNotAllocatorOrIntegral<_Hash>, @@ -1006,6 +1035,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER unordered_set<int>::size_type, _Allocator) -> unordered_set<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered container + template<typename _Tp, typename _Allocator, + typename = _RequireAllocator<_Allocator>> + unordered_set(initializer_list<_Tp>, _Allocator) + -> unordered_set<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; + template<typename _Tp, typename _Hash, typename _Allocator, typename = _RequireNotAllocatorOrIntegral<_Hash>, typename = _RequireAllocator<_Allocator>> @@ -1223,6 +1259,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : unordered_multiset(__n, __hf, key_equal(), __a) { } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered container + template<typename _InputIterator> + unordered_multiset(_InputIterator __first, _InputIterator __last, + const allocator_type& __a) + : unordered_multiset(__first, __last, 0, hasher(), key_equal(), __a) + { } + template<typename _InputIterator> unordered_multiset(_InputIterator __first, _InputIterator __last, size_type __n, @@ -1237,6 +1281,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : unordered_multiset(__first, __last, __n, __hf, key_equal(), __a) { } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered container + unordered_multiset(initializer_list<value_type> __l, + const allocator_type& __a) + : unordered_multiset(__l, 0, hasher(), key_equal(), __a) + { } + unordered_multiset(initializer_list<value_type> __l, size_type __n, const allocator_type& __a) @@ -1949,6 +2000,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator_traits<_InputIterator>::value_type>, _Allocator>; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered container + template<typename _InputIterator, typename _Allocator, + typename = _RequireInputIter<_InputIterator>, + typename = _RequireAllocator<_Allocator>> + unordered_multiset(_InputIterator, _InputIterator, _Allocator) + -> unordered_multiset<typename iterator_traits<_InputIterator>::value_type, + hash<typename + iterator_traits<_InputIterator>::value_type>, + equal_to<typename + iterator_traits<_InputIterator>::value_type>, + _Allocator>; + template<typename _InputIterator, typename _Hash, typename _Allocator, typename = _RequireInputIter<_InputIterator>, typename = _RequireNotAllocatorOrIntegral<_Hash>, @@ -1970,6 +2034,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER unordered_multiset<int>::size_type, _Allocator) -> unordered_multiset<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2713. More missing allocator-extended constructors for unordered container + template<typename _Tp, typename _Allocator, + typename = _RequireAllocator<_Allocator>> + unordered_multiset(initializer_list<_Tp>, _Allocator) + -> unordered_multiset<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; + template<typename _Tp, typename _Hash, typename _Allocator, typename = _RequireNotAllocatorOrIntegral<_Hash>, typename = _RequireAllocator<_Allocator>> diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h index 6fa6b67..4e57465 100644 --- a/libstdc++-v3/include/bits/utility.h +++ b/libstdc++-v3/include/bits/utility.h @@ -137,26 +137,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using tuple_element_t = typename tuple_element<__i, _Tp>::type; #endif - // Stores a tuple of indices. Used by tuple and pair, and by bind() to - // extract the elements in a tuple. - template<size_t... _Indexes> struct _Index_tuple { }; - - // Builds an _Index_tuple<0, 1, 2, ..., _Num-1>. - template<size_t _Num> - struct _Build_index_tuple - { -#if __has_builtin(__make_integer_seq) - template<typename, size_t... _Indices> - using _IdxTuple = _Index_tuple<_Indices...>; - - // Clang defines __make_integer_seq for this purpose. - using __type = __make_integer_seq<_IdxTuple, size_t, _Num>; -#else - // For GCC and other compilers, use __integer_pack instead. - using __type = _Index_tuple<__integer_pack(_Num)...>; -#endif - }; - #ifdef __glibcxx_integer_sequence // C++ >= 14 /// Class template integer_sequence @@ -316,6 +296,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/valarray_array.h b/libstdc++-v3/include/bits/valarray_array.h index 03b6f1e..b5c02b7 100644 --- a/libstdc++-v3/include/bits/valarray_array.h +++ b/libstdc++-v3/include/bits/valarray_array.h @@ -64,13 +64,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __valarray_release_memory(void* __p) { operator delete(__p); } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + // Turn raw-memory into an array of _Tp filled with _Tp(). // This is used in `valarray<T> v(n);` and in `valarray<T>::shift(n)`. template<typename _Tp> inline void __valarray_default_construct(_Tp* __b, _Tp* __e) { - if _GLIBCXX17_CONSTEXPR (__is_trivial(_Tp)) + if _GLIBCXX_CONSTEXPR (__is_trivial(_Tp)) __builtin_memset(__b, 0, (__e - __b) * sizeof(_Tp)); else while (__b != __e) @@ -94,7 +97,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __valarray_copy_construct(const _Tp* __b, const _Tp* __e, _Tp* __restrict__ __o) { - if _GLIBCXX17_CONSTEXPR (__is_trivial(_Tp)) + if _GLIBCXX_CONSTEXPR (__is_trivial(_Tp)) { if (__b) __builtin_memcpy(__o, __b, (__e - __b) * sizeof(_Tp)); @@ -110,7 +113,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __valarray_copy_construct (const _Tp* __restrict__ __a, size_t __n, size_t __s, _Tp* __restrict__ __o) { - if _GLIBCXX17_CONSTEXPR (__is_trivial(_Tp)) + if _GLIBCXX_CONSTEXPR (__is_trivial(_Tp)) while (__n--) { *__o++ = *__a; @@ -131,7 +134,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const size_t* __restrict__ __i, _Tp* __restrict__ __o, size_t __n) { - if (__is_trivial(_Tp)) + if _GLIBCXX_CONSTEXPR (__is_trivial(_Tp)) while (__n--) *__o++ = __a[*__i++]; else @@ -144,7 +147,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline void __valarray_destroy_elements(_Tp* __b, _Tp* __e) { - if (!__is_trivial(_Tp)) + if _GLIBCXX_CONSTEXPR (!__is_trivial(_Tp)) while (__b != __e) { __b->~_Tp(); @@ -152,6 +155,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } +#pragma GCC diagnostic pop + // Fill a plain array __a[<__n>] with __t template<typename _Tp> inline void diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index b21e1d3..642edb5 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -61,6 +61,9 @@ namespace std _GLIBCXX_VISIBILITY(default) _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_CONTAINER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + template<typename _Tp, typename _Alloc> _GLIBCXX20_CONSTEXPR void @@ -74,11 +77,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER const size_type __old_size = size(); pointer __tmp; #if __cplusplus >= 201103L - if _GLIBCXX17_CONSTEXPR (_S_use_relocate()) + if constexpr (_S_use_relocate()) { __tmp = this->_M_allocate(__n); - _S_relocate(this->_M_impl._M_start, this->_M_impl._M_finish, - __tmp, _M_get_Tp_allocator()); + std::__relocate_a(this->_M_impl._M_start, this->_M_impl._M_finish, + __tmp, _M_get_Tp_allocator()); } else #endif @@ -98,6 +101,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; } } +#pragma GCC diagnostic pop #if __cplusplus >= 201103L template<typename _Tp, typename _Alloc> @@ -444,6 +448,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr #if __cplusplus >= 201103L template<typename _Tp, typename _Alloc> template<typename... _Args> @@ -460,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(); @@ -488,14 +494,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif #if __cplusplus >= 201103L - if _GLIBCXX17_CONSTEXPR (_S_use_relocate()) + if constexpr (_S_use_relocate()) { // Relocation cannot throw. - __new_finish = _S_relocate(__old_start, __position.base(), - __new_start, _M_get_Tp_allocator()); + __new_finish = std::__relocate_a(__old_start, __position.base(), + __new_start, + _M_get_Tp_allocator()); ++__new_finish; - __new_finish = _S_relocate(__position.base(), __old_finish, - __new_finish, _M_get_Tp_allocator()); + __new_finish = std::__relocate_a(__position.base(), __old_finish, + __new_finish, + _M_get_Tp_allocator()); } else #endif @@ -565,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); @@ -593,11 +601,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif #if __cplusplus >= 201103L - if _GLIBCXX17_CONSTEXPR (_S_use_relocate()) + if constexpr (_S_use_relocate()) { // Relocation cannot throw. - __new_finish = _S_relocate(__old_start, __old_finish, - __new_start, _M_get_Tp_allocator()); + __new_finish = std::__relocate_a(__old_start, __old_finish, + __new_start, + _M_get_Tp_allocator()); ++__new_finish; } else @@ -645,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER this->_M_impl._M_finish = __new_finish; this->_M_impl._M_end_of_storage = __new_start + __len; } +#pragma GCC diagnostic pop template<typename _Tp, typename _Alloc> _GLIBCXX20_CONSTEXPR @@ -654,8 +664,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { if (__n != 0) { - if (size_type(this->_M_impl._M_end_of_storage - - this->_M_impl._M_finish) >= __n) + if (__position.base() == this->_M_impl._M_finish) + _M_fill_append(__n, __x); + else if (size_type(this->_M_impl._M_end_of_storage + - this->_M_impl._M_finish) >= __n) { #if __cplusplus < 201103L value_type __x_copy = __x; @@ -750,7 +762,63 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } } + template<typename _Tp, typename _Alloc> + _GLIBCXX20_CONSTEXPR + void + vector<_Tp, _Alloc>:: + _M_fill_append(size_type __n, const value_type& __x) + { + if (size_type(this->_M_impl._M_end_of_storage + - this->_M_impl._M_finish) >= __n) + { + _GLIBCXX_ASAN_ANNOTATE_GROW(__n); + this->_M_impl._M_finish = + std::__uninitialized_fill_n_a(this->_M_impl._M_finish, __n, __x, + _M_get_Tp_allocator()); + _GLIBCXX_ASAN_ANNOTATE_GREW(__n); + } + else + { + // Make local copies of these members because the compiler thinks + // the allocator can alter them if 'this' is globally reachable. + pointer __old_start = this->_M_impl._M_start; + pointer __old_finish = this->_M_impl._M_finish; + const size_type __old_size = __old_finish - __old_start; + + const size_type __len = + _M_check_len(__n, "vector::_M_fill_append"); + pointer __new_start(this->_M_allocate(__len)); + pointer __new_finish(__new_start + __old_size); + __try + { + // See _M_realloc_insert above. + __new_finish = std::__uninitialized_fill_n_a( + __new_finish, __n, __x, + _M_get_Tp_allocator()); + std::__uninitialized_move_if_noexcept_a( + __old_start, __old_finish, __new_start, + _M_get_Tp_allocator()); + } + __catch(...) + { + std::_Destroy(__new_start + __old_size, __new_finish, + _M_get_Tp_allocator()); + _M_deallocate(__new_start, __len); + __throw_exception_again; + } + std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator()); + _GLIBCXX_ASAN_ANNOTATE_REINIT; + _M_deallocate(__old_start, + this->_M_impl._M_end_of_storage - __old_start); + this->_M_impl._M_start = __new_start; + this->_M_impl._M_finish = __new_finish; + this->_M_impl._M_end_of_storage = __new_start + __len; + } + } + #if __cplusplus >= 201103L +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr template<typename _Tp, typename _Alloc> _GLIBCXX20_CONSTEXPR void @@ -794,10 +862,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER std::__uninitialized_default_n_a(__new_start + __size, __n, _M_get_Tp_allocator()); - if _GLIBCXX17_CONSTEXPR (_S_use_relocate()) + if constexpr (_S_use_relocate()) { - _S_relocate(__old_start, __old_finish, - __new_start, _M_get_Tp_allocator()); + std::__relocate_a(__old_start, __old_finish, + __new_start, _M_get_Tp_allocator()); } else { @@ -842,6 +910,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } } } +#pragma GCC diagnostic pop template<typename _Tp, typename _Alloc> _GLIBCXX20_CONSTEXPR @@ -994,15 +1063,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER if constexpr (ranges::forward_range<_Rg>) { + const auto __ins_idx = __pos - cbegin(); + // Number of new elements to insert: + const auto __n = size_type(ranges::distance(__rg)); + if (__n == 0) + return begin() + __ins_idx; + // Start of existing elements: pointer __old_start = this->_M_impl._M_start; // End of existing elements: pointer __old_finish = this->_M_impl._M_finish; // Insertion point: - const auto __ins_idx = __pos - cbegin(); pointer __ins = __old_start + __ins_idx; - // Number of new elements to insert: - const auto __n = size_type(ranges::distance(__rg)); // Number of elements that can fit in unused capacity: const auto __cap = this->_M_impl._M_end_of_storage - __old_finish; if (__cap >= __n) diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 0afaf0d..65b9a27 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -394,6 +394,14 @@ ftms = { }; ftms = { + name = constant_wrapper; + values = { + v = 202506; + cxxmin = 26; + }; +}; + +ftms = { name = has_unique_object_representations; values = { v = 201606; @@ -595,6 +603,16 @@ ftms = { }; ftms = { + // Unofficial macro for C++20 chrono features supported for old string ABI. + name = chrono_cxx20; + values = { + v = 201800; + cxxmin = 20; + no_stdname = yes; + }; +}; + +ftms = { name = execution; values = { v = 201902; // FIXME: should be 201603L @@ -649,7 +667,7 @@ ftms = { }; values = { v = 1; - /* For when there's no gthread. */ + // For when there is no gthread. cxxmin = 17; hosted = yes; gthread = no; @@ -679,8 +697,6 @@ ftms = { values = { v = 201703; cxxmin = 17; - hosted = yes; - gthread = yes; }; }; @@ -735,6 +751,14 @@ ftms = { }; ftms = { + name = is_sufficiently_aligned; + values = { + v = 202411; + cxxmin = 26; + }; +}; + +ftms = { name = atomic_flag_test; values = { v = 201907; @@ -854,6 +878,14 @@ ftms = { }; ftms = { + name = optional_range_support; + values = { + v = 202406; + cxxmin = 26; + }; +}; + +ftms = { name = destroying_delete; values = { v = 201806; @@ -959,6 +991,7 @@ ftms = { ftms = { name = make_obj_using_allocator; + no_stdname = true; values = { // Not specified by C++20, used internally v = 201811; @@ -999,6 +1032,28 @@ ftms = { }; ftms = { + name = mdspan; + values = { + v = 202406; + cxxmin = 26; + }; + values = { + v = 202207; + cxxmin = 23; + }; +}; + +ftms = { + name = aligned_accessor; + values = { + v = 202411; + cxxmin = 26; + extra_cond = "__glibcxx_assume_aligned " + "&& __glibcxx_is_sufficiently_aligned"; + }; +}; + +ftms = { name = ssize; values = { v = 201902; @@ -1076,6 +1131,10 @@ ftms = { ftms = { name = shift; values = { + v = 202202; + cxxmin = 23; + }; + values = { v = 201806; cxxmin = 20; }; @@ -1355,7 +1414,7 @@ ftms = { v = 201907; cxxmin = 20; hosted = yes; - extra_cond = "__glibcxx_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE"; + extra_cond = "__glibcxx_atomic_wait"; }; }; @@ -1416,9 +1475,8 @@ ftms = { // 202207 P2286R8 Formatting Ranges // 202207 P2585R1 Improving default container formatting // LWG3750 Too many papers bump __cpp_lib_format - no_stdname = true; // TODO remove values = { - v = 1; // TODO 202207 + v = 202207; cxxmin = 23; hosted = yes; }; @@ -1654,6 +1712,14 @@ ftms = { }; ftms = { + name = ranges_starts_ends_with; + values = { + v = 202106; + cxxmin = 23; + }; +}; + +ftms = { name = constexpr_bitset; values = { v = 202202; @@ -1741,6 +1807,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; @@ -1842,6 +1925,14 @@ ftms = { }; ftms = { + name = debugging; + values = { + v = 202403; + cxxmin = 26; + }; +}; + +ftms = { name = fstream_native_handle; values = { v = 202306; @@ -1945,6 +2036,87 @@ ftms = { }; }; +ftms = { + name = inplace_vector; + values = { + v = 202406; + cxxmin = 26; + }; +}; + +ftms = { + name = indirect; + values = { + v = 202502; + cxxmin = 26; + hosted = yes; + }; +}; + +ftms = { + name = polymorphic; + values = { + v = 202502; + cxxmin = 26; + hosted = yes; + }; +}; + +ftms = { + name = smart_ptr_owner_equality; + values = { + v = 202306; + 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; + }; +}; + +ftms = { + name = bitset; // ...construct from string_view + values = { + v = 202306; + cxxmin = 26; + }; +}; + +ftms = { + name = constexpr_exceptions; + // TODO Remove when PR121114 is resolved + no_stdname = true; + values = { + v = 1; // TODO 202411; + cxxmin = 26; + extra_cond = "__cpp_constexpr_exceptions >= 202411L"; + }; +}; + // 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 980fee6..b052498 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -430,6 +430,16 @@ #endif /* !defined(__cpp_lib_byte) && defined(__glibcxx_want_byte) */ #undef __glibcxx_want_byte +#if !defined(__cpp_lib_constant_wrapper) +# if (__cplusplus > 202302L) +# define __glibcxx_constant_wrapper 202506L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constant_wrapper) +# define __cpp_lib_constant_wrapper 202506L +# endif +# endif +#endif /* !defined(__cpp_lib_constant_wrapper) && defined(__glibcxx_want_constant_wrapper) */ +#undef __glibcxx_want_constant_wrapper + #if !defined(__cpp_lib_has_unique_object_representations) # if (__cplusplus >= 201703L) && (defined(_GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP)) # define __glibcxx_has_unique_object_representations 201606L @@ -665,6 +675,15 @@ #endif /* !defined(__cpp_lib_chrono) && defined(__glibcxx_want_chrono) */ #undef __glibcxx_want_chrono +#if !defined(__cpp_lib_chrono_cxx20) +# if (__cplusplus >= 202002L) +# define __glibcxx_chrono_cxx20 201800L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_chrono_cxx20) +# endif +# endif +#endif /* !defined(__cpp_lib_chrono_cxx20) && defined(__glibcxx_want_chrono_cxx20) */ +#undef __glibcxx_want_chrono_cxx20 + #if !defined(__cpp_lib_execution) # if (__cplusplus >= 201703L) && _GLIBCXX_HOSTED # define __glibcxx_execution 201902L @@ -751,7 +770,7 @@ #undef __glibcxx_want_parallel_algorithm #if !defined(__cpp_lib_scoped_lock) -# if (__cplusplus >= 201703L) && defined(_GLIBCXX_HAS_GTHREADS) && _GLIBCXX_HOSTED +# if (__cplusplus >= 201703L) # define __glibcxx_scoped_lock 201703L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_scoped_lock) # define __cpp_lib_scoped_lock 201703L @@ -815,6 +834,16 @@ #endif /* !defined(__cpp_lib_assume_aligned) && defined(__glibcxx_want_assume_aligned) */ #undef __glibcxx_want_assume_aligned +#if !defined(__cpp_lib_is_sufficiently_aligned) +# if (__cplusplus > 202302L) +# define __glibcxx_is_sufficiently_aligned 202411L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_sufficiently_aligned) +# define __cpp_lib_is_sufficiently_aligned 202411L +# endif +# endif +#endif /* !defined(__cpp_lib_is_sufficiently_aligned) && defined(__glibcxx_want_is_sufficiently_aligned) */ +#undef __glibcxx_want_is_sufficiently_aligned + #if !defined(__cpp_lib_atomic_flag_test) # if (__cplusplus >= 202002L) # define __glibcxx_atomic_flag_test 201907L @@ -955,6 +984,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 @@ -1074,7 +1113,6 @@ # if (__cplusplus >= 202002L) && (__cpp_concepts) # define __glibcxx_make_obj_using_allocator 201811L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_make_obj_using_allocator) -# define __cpp_lib_make_obj_using_allocator 201811L # endif # endif #endif /* !defined(__cpp_lib_make_obj_using_allocator) && defined(__glibcxx_want_make_obj_using_allocator) */ @@ -1115,6 +1153,31 @@ #endif /* !defined(__cpp_lib_span) && defined(__glibcxx_want_span) */ #undef __glibcxx_want_span +#if !defined(__cpp_lib_mdspan) +# if (__cplusplus > 202302L) +# define __glibcxx_mdspan 202406L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_mdspan) +# define __cpp_lib_mdspan 202406L +# endif +# elif (__cplusplus >= 202100L) +# define __glibcxx_mdspan 202207L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_mdspan) +# define __cpp_lib_mdspan 202207L +# endif +# endif +#endif /* !defined(__cpp_lib_mdspan) && defined(__glibcxx_want_mdspan) */ +#undef __glibcxx_want_mdspan + +#if !defined(__cpp_lib_aligned_accessor) +# if (__cplusplus > 202302L) && (__glibcxx_assume_aligned && __glibcxx_is_sufficiently_aligned) +# define __glibcxx_aligned_accessor 202411L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_aligned_accessor) +# define __cpp_lib_aligned_accessor 202411L +# endif +# endif +#endif /* !defined(__cpp_lib_aligned_accessor) && defined(__glibcxx_want_aligned_accessor) */ +#undef __glibcxx_want_aligned_accessor + #if !defined(__cpp_lib_ssize) # if (__cplusplus >= 202002L) # define __glibcxx_ssize 201902L @@ -1206,7 +1269,12 @@ #undef __glibcxx_want_constexpr_utility #if !defined(__cpp_lib_shift) -# if (__cplusplus >= 202002L) +# if (__cplusplus >= 202100L) +# define __glibcxx_shift 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_shift) +# define __cpp_lib_shift 202202L +# endif +# elif (__cplusplus >= 202002L) # define __glibcxx_shift 201806L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_shift) # define __cpp_lib_shift 201806L @@ -1491,7 +1559,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 @@ -1562,8 +1630,9 @@ #if !defined(__cpp_lib_format_ranges) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED -# define __glibcxx_format_ranges 1L +# define __glibcxx_format_ranges 202207L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_format_ranges) +# define __cpp_lib_format_ranges 202207L # endif # endif #endif /* !defined(__cpp_lib_format_ranges) && defined(__glibcxx_want_format_ranges) */ @@ -1839,6 +1908,16 @@ #endif /* !defined(__cpp_lib_ranges_find_last) && defined(__glibcxx_want_ranges_find_last) */ #undef __glibcxx_want_ranges_find_last +#if !defined(__cpp_lib_ranges_starts_ends_with) +# if (__cplusplus >= 202100L) +# define __glibcxx_ranges_starts_ends_with 202106L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_starts_ends_with) +# define __cpp_lib_ranges_starts_ends_with 202106L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_starts_ends_with) && defined(__glibcxx_want_ranges_starts_ends_with) */ +#undef __glibcxx_want_ranges_starts_ends_with + #if !defined(__cpp_lib_constexpr_bitset) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED && (__cpp_constexpr_dynamic_alloc) # define __glibcxx_constexpr_bitset 202202L @@ -1939,6 +2018,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 @@ -2054,6 +2153,16 @@ #endif /* !defined(__cpp_lib_constexpr_new) && defined(__glibcxx_want_constexpr_new) */ #undef __glibcxx_want_constexpr_new +#if !defined(__cpp_lib_debugging) +# if (__cplusplus > 202302L) +# define __glibcxx_debugging 202403L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_debugging) +# define __cpp_lib_debugging 202403L +# endif +# endif +#endif /* !defined(__cpp_lib_debugging) && defined(__glibcxx_want_debugging) */ +#undef __glibcxx_want_debugging + #if !defined(__cpp_lib_fstream_native_handle) # if (__cplusplus > 202302L) && _GLIBCXX_HOSTED # define __glibcxx_fstream_native_handle 202306L @@ -2174,4 +2283,93 @@ #endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) */ #undef __glibcxx_want_modules +#if !defined(__cpp_lib_inplace_vector) +# if (__cplusplus > 202302L) +# define __glibcxx_inplace_vector 202406L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_inplace_vector) +# define __cpp_lib_inplace_vector 202406L +# endif +# endif +#endif /* !defined(__cpp_lib_inplace_vector) && defined(__glibcxx_want_inplace_vector) */ +#undef __glibcxx_want_inplace_vector + +#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_smart_ptr_owner_equality) +# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED +# define __glibcxx_smart_ptr_owner_equality 202306L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_smart_ptr_owner_equality) +# define __cpp_lib_smart_ptr_owner_equality 202306L +# endif +# endif +#endif /* !defined(__cpp_lib_smart_ptr_owner_equality) && defined(__glibcxx_want_smart_ptr_owner_equality) */ +#undef __glibcxx_want_smart_ptr_owner_equality + +#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 + +#if !defined(__cpp_lib_bitset) +# if (__cplusplus > 202302L) +# define __glibcxx_bitset 202306L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_bitset) +# define __cpp_lib_bitset 202306L +# endif +# endif +#endif /* !defined(__cpp_lib_bitset) && defined(__glibcxx_want_bitset) */ +#undef __glibcxx_want_bitset + +#if !defined(__cpp_lib_constexpr_exceptions) +# if (__cplusplus > 202302L) && (__cpp_constexpr_exceptions >= 202411L) +# define __glibcxx_constexpr_exceptions 1L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_exceptions) +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_exceptions) && defined(__glibcxx_want_constexpr_exceptions) */ +#undef __glibcxx_want_constexpr_exceptions + #undef __glibcxx_want_all diff --git a/libstdc++-v3/include/c_global/ccomplex b/libstdc++-v3/include/c_global/ccomplex index 7044cf7..a39273f 100644 --- a/libstdc++-v3/include/c_global/ccomplex +++ b/libstdc++-v3/include/c_global/ccomplex @@ -24,6 +24,8 @@ /** @file include/ccomplex * This is a Standard C++ Library header. + * + * @since C++11 (removed in C++20) */ #ifndef _GLIBCXX_CCOMPLEX diff --git a/libstdc++-v3/include/c_global/ciso646 b/libstdc++-v3/include/c_global/ciso646 index a663e04..6dec7df 100644 --- a/libstdc++-v3/include/c_global/ciso646 +++ b/libstdc++-v3/include/c_global/ciso646 @@ -28,6 +28,8 @@ * * This is the C++ version of the Standard C Library header @c iso646.h, * which is empty in C++. + * + * @since C++11 (removed in C++20) */ #ifndef _GLIBCXX_CISO646 #define _GLIBCXX_CISO646 @@ -38,13 +40,15 @@ #include <bits/c++config.h> -#if __cplusplus >= 202002L && ! _GLIBCXX_USE_DEPRECATED -# error "<ciso646> is not a standard header in C++20, use <version> to detect implementation-specific macros" -#elif __cplusplus >= 201703L && defined __DEPRECATED -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wc++23-extensions" -# warning "<ciso646> is deprecated in C++17, use <version> to detect implementation-specific macros" -# pragma GCC diagnostic pop +#if __cplusplus >= 202002L +# if ! _GLIBCXX_USE_DEPRECATED +# error "<ciso646> is not a standard header since C++20, use <version> to detect implementation-specific macros" +# elif defined __DEPRECATED +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wc++23-extensions" +# warning "<ciso646> is not a standard header since C++20, use <version> to detect implementation-specific macros" +# pragma GCC diagnostic pop +# endif #endif #endif diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath index 27c21ca..65a3b81 100644 --- a/libstdc++-v3/include/c_global/cmath +++ b/libstdc++-v3/include/c_global/cmath @@ -3792,10 +3792,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return std::__hypot3<long double>(__x, __y, __z); } template<typename _Tp, typename _Up, typename _Vp> - __gnu_cxx::__promoted_t<_Tp, _Up, _Vp> + typename __gnu_cxx::__promote_3<_Tp, _Up, _Vp>::__type hypot(_Tp __x, _Up __y, _Vp __z) { - using __type = __gnu_cxx::__promoted_t<_Tp, _Up, _Vp>; + using __type = typename __gnu_cxx::__promote_3<_Tp, _Up, _Vp>::__type; return std::__hypot3<__type>(__x, __y, __z); } diff --git a/libstdc++-v3/include/c_global/cstdalign b/libstdc++-v3/include/c_global/cstdalign index 92e0ad6..41ce506 100644 --- a/libstdc++-v3/include/c_global/cstdalign +++ b/libstdc++-v3/include/c_global/cstdalign @@ -24,6 +24,8 @@ /** @file include/cstdalign * This is a Standard C++ Library header. + * + * @since C++11 (removed in C++20) */ #ifndef _GLIBCXX_CSTDALIGN diff --git a/libstdc++-v3/include/c_global/cstdbool b/libstdc++-v3/include/c_global/cstdbool index e75f56c..5933d7d 100644 --- a/libstdc++-v3/include/c_global/cstdbool +++ b/libstdc++-v3/include/c_global/cstdbool @@ -24,6 +24,8 @@ /** @file include/cstdbool * This is a Standard C++ Library header. + * + * @since C++11 (removed in C++20) */ #ifndef _GLIBCXX_CSTDBOOL diff --git a/libstdc++-v3/include/c_global/ctgmath b/libstdc++-v3/include/c_global/ctgmath index 0a5a0e7..b708878 100644 --- a/libstdc++-v3/include/c_global/ctgmath +++ b/libstdc++-v3/include/c_global/ctgmath @@ -24,6 +24,8 @@ /** @file include/ctgmath * This is a Standard C++ Library header. + * + * @since C++11 (removed in C++20) */ #ifndef _GLIBCXX_CTGMATH diff --git a/libstdc++-v3/include/debug/bitset b/libstdc++-v3/include/debug/bitset index ad9b7b5..2f4bab8 100644 --- a/libstdc++-v3/include/debug/bitset +++ b/libstdc++-v3/include/debug/bitset @@ -164,11 +164,28 @@ namespace __debug _CharT __zero, _CharT __one = _CharT('1')) : _Base(__str, __pos, __n, __zero, __one) { } +#ifdef __cpp_lib_bitset // ... from string_view + template<class _CharT, class _Traits> + constexpr explicit + bitset(std::basic_string_view<_CharT, _Traits> __s, + std::basic_string_view<_CharT, _Traits>::size_type __position = 0, + std::basic_string_view<_CharT, _Traits>::size_type __n = + std::basic_string_view<_CharT, _Traits>::npos, + _CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) + : _Base(__s, __position, __n, __zero, __one) { } +#endif + _GLIBCXX23_CONSTEXPR bitset(const _Base& __x) : _Base(__x) { } #if __cplusplus >= 201103L - template<typename _CharT> + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4294. bitset(const CharT*) constructor needs to be constrained + template<typename _CharT, + typename = _Require<is_trivially_copyable<_CharT>, + is_standard_layout<_CharT>, + is_trivially_default_constructible<_CharT>, + __not_<is_array<_CharT>>>> _GLIBCXX23_CONSTEXPR explicit bitset(const _CharT* __str, diff --git a/libstdc++-v3/include/debug/debug.h b/libstdc++-v3/include/debug/debug.h index 0e02d58..0131c0a 100644 --- a/libstdc++-v3/include/debug/debug.h +++ b/libstdc++-v3/include/debug/debug.h @@ -58,7 +58,7 @@ namespace __gnu_debug using namespace std::__debug; template<typename _Ite, typename _Seq, typename _Cat> - struct _Safe_iterator; + class _Safe_iterator; } #if ! defined _GLIBCXX_DEBUG || ! _GLIBCXX_HOSTED diff --git a/libstdc++-v3/include/debug/deque b/libstdc++-v3/include/debug/deque index 59d60b2..ed69eb8 100644 --- a/libstdc++-v3/include/debug/deque +++ b/libstdc++-v3/include/debug/deque @@ -650,7 +650,8 @@ namespace __debug else if (__first.base() == _Base::begin() || __last.base() == _Base::end()) { - this->_M_detach_singular(); + const deque* __this = this; + __this->_M_detach_singular(); for (_Base_const_iterator __position = __first.base(); __position != __last.base(); ++__position) { @@ -663,7 +664,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h index d80e8a7..8aa84ad 100644 --- a/libstdc++-v3/include/debug/formatter.h +++ b/libstdc++-v3/include/debug/formatter.h @@ -96,7 +96,7 @@ namespace __gnu_debug template<typename _Iterator, typename _Sequence, typename _Category> class _Safe_iterator; - template<typename _Iterator, typename _Sequence> + template<typename _Iterator, typename _UContainer> class _Safe_local_iterator; template<typename _Sequence> @@ -316,8 +316,8 @@ namespace __gnu_debug } } - template<typename _Iterator, typename _Sequence> - _Parameter(_Safe_local_iterator<_Iterator, _Sequence> const& __it, + template<typename _Iterator, typename _UContainer> + _Parameter(_Safe_local_iterator<_Iterator, _UContainer> const& __it, const char* __name, _Is_iterator) : _M_kind(__iterator), _M_variant() { @@ -326,8 +326,8 @@ namespace __gnu_debug _M_variant._M_iterator._M_type = _GLIBCXX_TYPEID(_Iterator); _M_variant._M_iterator._M_constness = __it._S_constant() ? __const_iterator : __mutable_iterator; - _M_variant._M_iterator._M_sequence = __it._M_get_sequence(); - _M_variant._M_iterator._M_seq_type = _GLIBCXX_TYPEID(_Sequence); + _M_variant._M_iterator._M_sequence = __it._M_get_ucontainer(); + _M_variant._M_iterator._M_seq_type = _GLIBCXX_TYPEID(_UContainer); if (__it._M_singular()) { diff --git a/libstdc++-v3/include/debug/forward_list b/libstdc++-v3/include/debug/forward_list index 60a2542..9da7dda 100644 --- a/libstdc++-v3/include/debug/forward_list +++ b/libstdc++-v3/include/debug/forward_list @@ -58,44 +58,44 @@ namespace __gnu_debug class _Safe_forward_list : public _Safe_sequence<_SafeSequence> { - _SafeSequence& - _M_this() noexcept - { return *static_cast<_SafeSequence*>(this); } + const _SafeSequence* + _M_this() const noexcept + { return static_cast<const _SafeSequence*>(this); } static void - _M_swap_aux(_Safe_sequence_base& __lhs, + _S_swap_aux(const _Safe_forward_list& __lhs, _Safe_iterator_base*& __lhs_iterators, - _Safe_sequence_base& __rhs, + const _Safe_forward_list& __rhs, _Safe_iterator_base*& __rhs_iterators); - void _M_swap_single(_Safe_sequence_base&) noexcept; + void _M_swap_single(const _Safe_forward_list&) const noexcept; protected: void - _M_invalidate_all() + _M_invalidate_all() const { - using _Base_const_iterator = __decltype(_M_this()._M_base().cend()); + using _Base_const_iterator = __decltype(_M_this()->_M_base().cend()); this->_M_invalidate_if([this](_Base_const_iterator __it) { - return __it != _M_this()._M_base().cbefore_begin() - && __it != _M_this()._M_base().cend(); }); + return __it != _M_this()->_M_base().cbefore_begin() + && __it != _M_this()->_M_base().cend(); }); } - void _M_swap(_Safe_sequence_base&) noexcept; + void + _M_swap(const _Safe_forward_list&) const noexcept; }; template<typename _SafeSequence> void _Safe_forward_list<_SafeSequence>:: - _M_swap_aux(_Safe_sequence_base& __lhs, + _S_swap_aux(const _Safe_forward_list& __lhs, _Safe_iterator_base*& __lhs_iterators, - _Safe_sequence_base& __rhs, + const _Safe_forward_list& __rhs, _Safe_iterator_base*& __rhs_iterators) { using const_iterator = typename _SafeSequence::const_iterator; _Safe_iterator_base* __bbegin_its = 0; _Safe_iterator_base* __last_bbegin = 0; - _SafeSequence& __rseq = static_cast<_SafeSequence&>(__rhs); for (_Safe_iterator_base* __iter = __lhs_iterators; __iter;) { @@ -104,7 +104,7 @@ namespace __gnu_debug const_iterator* __victim = static_cast<const_iterator*>(__victim_base); __iter = __iter->_M_next; - if (__victim->base() == __rseq._M_base().cbefore_begin()) + if (__victim->base() == __rhs._M_this()->_M_base().cbefore_begin()) { __victim->_M_unlink(); if (__lhs_iterators == __victim_base) @@ -136,21 +136,21 @@ namespace __gnu_debug template<typename _SafeSequence> void _Safe_forward_list<_SafeSequence>:: - _M_swap_single(_Safe_sequence_base& __other) noexcept + _M_swap_single(const _Safe_forward_list& __other) const noexcept { - std::swap(_M_this()._M_iterators, __other._M_iterators); - std::swap(_M_this()._M_const_iterators, __other._M_const_iterators); + std::swap(_M_this()->_M_iterators, __other._M_iterators); + std::swap(_M_this()->_M_const_iterators, __other._M_const_iterators); // Useless, always 1 on forward_list - //std::swap(_M_this()_M_version, __other._M_version); - _Safe_iterator_base* __this_its = _M_this()._M_iterators; - _M_swap_aux(__other, __other._M_iterators, - _M_this(), _M_this()._M_iterators); - _Safe_iterator_base* __this_const_its = _M_this()._M_const_iterators; - _M_swap_aux(__other, __other._M_const_iterators, - _M_this(), _M_this()._M_const_iterators); - _M_swap_aux(_M_this(), __this_its, + //std::swap(_M_this()->_M_version, __other._M_version); + _Safe_iterator_base* __this_its = _M_this()->_M_iterators; + _S_swap_aux(__other, __other._M_iterators, + *_M_this(), _M_this()->_M_iterators); + _Safe_iterator_base* __this_const_its = _M_this()->_M_const_iterators; + _S_swap_aux(__other, __other._M_const_iterators, + *_M_this(), _M_this()->_M_const_iterators); + _S_swap_aux(*_M_this(), __this_its, __other, __other._M_iterators); - _M_swap_aux(_M_this(), __this_const_its, + _S_swap_aux(*_M_this(), __this_const_its, __other, __other._M_const_iterators); } @@ -159,13 +159,12 @@ namespace __gnu_debug template<typename _SafeSequence> void _Safe_forward_list<_SafeSequence>:: - _M_swap(_Safe_sequence_base& __other) noexcept + _M_swap(const _Safe_forward_list& __other) const noexcept { // We need to lock both sequences to swap using namespace __gnu_cxx; - __mutex *__this_mutex = &_M_this()._M_get_mutex(); - __mutex *__other_mutex = - &static_cast<_SafeSequence&>(__other)._M_get_mutex(); + __mutex *__this_mutex = &_M_this()->_M_get_mutex(); + __mutex *__other_mutex = &__other._M_get_mutex(); if (__this_mutex == __other_mutex) { __scoped_lock __lock(*__this_mutex); @@ -565,7 +564,8 @@ namespace __debug void resize(size_type __sz) { - this->_M_detach_singular(); + const forward_list* __this = this; + __this->_M_detach_singular(); // if __sz < size(), invalidate all iterators in [begin+__sz, end() _Base_iterator __victim = _Base::begin(); @@ -585,7 +585,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } @@ -593,7 +593,8 @@ namespace __debug void resize(size_type __sz, const value_type& __val) { - this->_M_detach_singular(); + const forward_list* __this = this; + __this->_M_detach_singular(); // if __sz < size(), invalidate all iterators in [begin+__sz, end()) _Base_iterator __victim = _Base::begin(); @@ -613,7 +614,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list index a9d974c..c502c7c 100644 --- a/libstdc++-v3/include/debug/list +++ b/libstdc++-v3/include/debug/list @@ -321,7 +321,8 @@ namespace __debug void resize(size_type __sz) { - this->_M_detach_singular(); + const list* __this = this; + __this->_M_detach_singular(); // if __sz < size(), invalidate all iterators in [begin + __sz, end()) _Base_iterator __victim = _Base::begin(); @@ -338,7 +339,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } @@ -346,7 +347,8 @@ namespace __debug void resize(size_type __sz, const _Tp& __c) { - this->_M_detach_singular(); + const list* __this = this; + __this->_M_detach_singular(); // if __sz < size(), invalidate all iterators in [begin + __sz, end()) _Base_iterator __victim = _Base::begin(); @@ -363,7 +365,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } @@ -371,7 +373,8 @@ namespace __debug void resize(size_type __sz, _Tp __c = _Tp()) { - this->_M_detach_singular(); + const list* __this = this; + __this->_M_detach_singular(); // if __sz < size(), invalidate all iterators in [begin + __sz, end()) _Base_iterator __victim = _Base::begin(); @@ -388,7 +391,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } diff --git a/libstdc++-v3/include/debug/safe_base.h b/libstdc++-v3/include/debug/safe_base.h index cf3f170..4462297 100644 --- a/libstdc++-v3/include/debug/safe_base.h +++ b/libstdc++-v3/include/debug/safe_base.h @@ -53,8 +53,10 @@ namespace __gnu_debug public: /** The sequence this iterator references; may be NULL to indicate - a singular iterator. */ - _Safe_sequence_base* _M_sequence; + * a singular iterator. Stored as pointer-to-const because sequence + * could be declared as const. + */ + const _Safe_sequence_base* _M_sequence; /** The version number of this iterator. The sentinel value 0 is * used to indicate an invalidated iterator (i.e., one that is @@ -92,7 +94,7 @@ namespace __gnu_debug : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0) { if (!std::__is_constant_evaluated()) - this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); + this->_M_attach(__seq, __constant); } /** Initializes the iterator to reference the same sequence that @@ -115,7 +117,7 @@ namespace __gnu_debug /** For use in _Safe_iterator. */ __gnu_cxx::__mutex& - _M_get_mutex() throw (); + _M_get_mutex() _GLIBCXX_USE_NOEXCEPT; /** Attaches this iterator to the given sequence, detaching it * from whatever sequence it was attached to originally. If the @@ -123,11 +125,12 @@ namespace __gnu_debug * unattached. */ void - _M_attach(_Safe_sequence_base* __seq, bool __constant); + _M_attach(const _Safe_sequence_base* __seq, bool __constant); /** Likewise, but not thread-safe. */ void - _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw (); + _M_attach_single(const _Safe_sequence_base* __seq, + bool __constant) _GLIBCXX_USE_NOEXCEPT; /** Detach the iterator for whatever sequence it is attached to, * if any. @@ -135,10 +138,23 @@ namespace __gnu_debug void _M_detach(); +#if !_GLIBCXX_INLINE_VERSION + private: + /***************************************************************/ + /** Not-const method preserved for abi backward compatibility. */ + void + _M_attach(_Safe_sequence_base* __seq, bool __constant); + + void + _M_attach_single(_Safe_sequence_base* __seq, + bool __constant) _GLIBCXX_USE_NOEXCEPT; + /***************************************************************/ +#endif + public: /** Likewise, but not thread-safe. */ void - _M_detach_single() throw (); + _M_detach_single() _GLIBCXX_USE_NOEXCEPT; /** Determines if we are attached to the given sequence. */ bool @@ -147,13 +163,13 @@ namespace __gnu_debug /** Is this iterator singular? */ _GLIBCXX_PURE bool - _M_singular() const throw (); + _M_singular() const _GLIBCXX_USE_NOEXCEPT; /** Can we compare this iterator to the given iterator @p __x? Returns true if both iterators are nonsingular and reference the same sequence. */ _GLIBCXX_PURE bool - _M_can_compare(const _Safe_iterator_base& __x) const throw (); + _M_can_compare(const _Safe_iterator_base& __x) const _GLIBCXX_USE_NOEXCEPT; /** Invalidate the iterator, making it singular. */ void @@ -162,11 +178,11 @@ namespace __gnu_debug /** Reset all member variables */ void - _M_reset() throw (); + _M_reset() _GLIBCXX_USE_NOEXCEPT; /** Unlink itself */ void - _M_unlink() throw () + _M_unlink() _GLIBCXX_USE_NOEXCEPT { if (_M_prior) _M_prior->_M_next = _M_next; @@ -246,14 +262,14 @@ namespace __gnu_debug /** Detach all iterators, leaving them singular. */ void - _M_detach_all(); + _M_detach_all() const; /** Detach all singular iterators. * @post for all iterators i attached to this sequence, * i->_M_version == _M_version. */ void - _M_detach_singular(); + _M_detach_singular() const; /** Revalidates all attached singular iterators. This method may * be used to validate iterators that were invalidated before @@ -261,7 +277,7 @@ namespace __gnu_debug * valid again). */ void - _M_revalidate_singular(); + _M_revalidate_singular() const; /** Swap this sequence with the given sequence. This operation * also swaps ownership of the iterators, so that when the @@ -269,11 +285,11 @@ namespace __gnu_debug * one container now reference the other container. */ void - _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT; + _M_swap(const _Safe_sequence_base& __x) const _GLIBCXX_USE_NOEXCEPT; /** For use in _Safe_sequence. */ __gnu_cxx::__mutex& - _M_get_mutex() throw (); + _M_get_mutex() const _GLIBCXX_USE_NOEXCEPT; /** Invalidates all iterators. */ void @@ -281,21 +297,42 @@ namespace __gnu_debug { if (++_M_version == 0) _M_version = 1; } private: +#if !_GLIBCXX_INLINE_VERSION + /***************************************************************/ + /** Not-const method preserved for abi backward compatibility. */ + void + _M_detach_all(); + + void + _M_detach_singular(); + + void + _M_revalidate_singular(); + + void + _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT; + + __gnu_cxx::__mutex& + _M_get_mutex() _GLIBCXX_USE_NOEXCEPT; + /***************************************************************/ +#endif + /** Attach an iterator to this sequence. */ void - _M_attach(_Safe_iterator_base* __it, bool __constant); + _M_attach(_Safe_iterator_base* __it, bool __constant) const; /** Likewise but not thread safe. */ void - _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw (); + _M_attach_single(_Safe_iterator_base* __it, + bool __constant) const _GLIBCXX_USE_NOEXCEPT; /** Detach an iterator from this sequence */ void - _M_detach(_Safe_iterator_base* __it); + _M_detach(_Safe_iterator_base* __it) const; /** Likewise but not thread safe. */ void - _M_detach_single(_Safe_iterator_base* __it) throw (); + _M_detach_single(_Safe_iterator_base* __it) const _GLIBCXX_USE_NOEXCEPT; }; } // namespace __gnu_debug diff --git a/libstdc++-v3/include/debug/safe_container.h b/libstdc++-v3/include/debug/safe_container.h index cb1e69a..3341806 100644 --- a/libstdc++-v3/include/debug/safe_container.h +++ b/libstdc++-v3/include/debug/safe_container.h @@ -44,9 +44,9 @@ namespace __gnu_debug typedef _SafeBase<_SafeContainer> _Base; _GLIBCXX20_CONSTEXPR - _SafeContainer& - _M_cont() _GLIBCXX_NOEXCEPT - { return *static_cast<_SafeContainer*>(this); } + const _SafeContainer& + _M_cont() const _GLIBCXX_NOEXCEPT + { return *static_cast<const _SafeContainer*>(this); } protected: #if __cplusplus >= 201103L @@ -56,6 +56,11 @@ namespace __gnu_debug private: _GLIBCXX20_CONSTEXPR + void + _M_swap_base(const _Safe_container& __x) const noexcept + { _Base::_M_swap(__x); } + + _GLIBCXX20_CONSTEXPR _Safe_container(_Safe_container&& __x, const _Alloc&, std::true_type) : _Safe_container(std::move(__x)) { } @@ -67,7 +72,7 @@ namespace __gnu_debug if (!std::__is_constant_evaluated()) { if (__x._M_cont().get_allocator() == __a) - _Base::_M_swap(__x); + _M_swap_base(__x); else __x._M_invalidate_all(); } @@ -115,12 +120,12 @@ namespace __gnu_debug bool __xfer_memory = _Alloc_traits::_S_propagate_on_move_assign() || _M_cont().get_allocator() == __x._M_cont().get_allocator(); if (__xfer_memory) - _Base::_M_swap(__x); + _M_swap_base(__x); else this->_M_invalidate_all(); } else - _Base::_M_swap(__x); + _M_swap_base(__x); __x._M_invalidate_all(); return *this; @@ -128,7 +133,7 @@ namespace __gnu_debug _GLIBCXX20_CONSTEXPR void - _M_swap(_Safe_container& __x) noexcept + _M_swap(const _Safe_container& __x) const noexcept { if (_IsCxx11AllocatorAware) { @@ -139,8 +144,12 @@ namespace __gnu_debug __x._M_cont()._M_base()); } - _Base::_M_swap(__x); + _M_swap_base(__x); } +#else + void + _M_swap(const _Safe_container& __x) const throw() + { _Base::_M_swap(__x); } #endif }; diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h index 7c56338..e0b1b46 100644 --- a/libstdc++-v3/include/debug/safe_iterator.h +++ b/libstdc++-v3/include/debug/safe_iterator.h @@ -224,7 +224,7 @@ namespace __gnu_debug _M_message(__msg_init_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); - _Safe_sequence_base* __seq = __x._M_sequence; + const _Safe_sequence_base* __seq = __x._M_sequence; __x._M_detach(); std::swap(base(), __x.base()); _M_attach(__seq); @@ -445,12 +445,12 @@ namespace __gnu_debug /** Attach iterator to the given sequence. */ void - _M_attach(_Safe_sequence_base* __seq) + _M_attach(const _Safe_sequence_base* __seq) { _Safe_base::_M_attach(__seq, _S_constant()); } /** Likewise, but not thread-safe. */ void - _M_attach_single(_Safe_sequence_base* __seq) + _M_attach_single(const _Safe_sequence_base* __seq) { _Safe_base::_M_attach_single(__seq, _S_constant()); } /// Is the iterator dereferenceable? @@ -500,7 +500,13 @@ namespace __gnu_debug typename __gnu_cxx::__conditional_type< _IsConstant::__value, const _Sequence*, _Sequence*>::__type _M_get_sequence() const - { return static_cast<_Sequence*>(_M_sequence); } + { + // Looks like not const-correct, but if _IsConstant the constness + // is restored when returning the sequence pointer and if not + // _IsConstant we are allowed to remove constness. + return static_cast<_Sequence*> + (const_cast<_Safe_sequence_base*>(_M_sequence)); + } // Get distance to __rhs. typename _Distance_traits<_Iterator>::__type diff --git a/libstdc++-v3/include/debug/safe_local_iterator.h b/libstdc++-v3/include/debug/safe_local_iterator.h index c84f4f1..47b3a80 100644 --- a/libstdc++-v3/include/debug/safe_local_iterator.h +++ b/libstdc++-v3/include/debug/safe_local_iterator.h @@ -52,15 +52,15 @@ namespace __gnu_debug /** \brief Safe iterator wrapper. * * The class template %_Safe_local_iterator is a wrapper around an - * iterator that tracks the iterator's movement among sequences and - * checks that operations performed on the "safe" iterator are + * iterator that tracks the iterator's movement among unordered containers + * and checks that operations performed on the "safe" iterator are * legal. In additional to the basic iterator operations (which are * validated, and then passed to the underlying iterator), * %_Safe_local_iterator has member functions for iterator invalidation, - * attaching/detaching the iterator from sequences, and querying + * attaching/detaching the iterator from unordered containers, and querying * the iterator's state. */ - template<typename _Iterator, typename _Sequence> + template<typename _Iterator, typename _UContainer> class _Safe_local_iterator : private _Iterator , public _Safe_local_iterator_base @@ -68,28 +68,27 @@ namespace __gnu_debug typedef _Iterator _Iter_base; typedef _Safe_local_iterator_base _Safe_base; - typedef typename _Sequence::size_type size_type; + typedef typename _UContainer::size_type size_type; typedef std::iterator_traits<_Iterator> _Traits; - typedef std::__are_same< - typename _Sequence::_Base::const_local_iterator, - _Iterator> _IsConstant; + using _IsConstant = std::__are_same< + typename _UContainer::_Base::const_local_iterator, _Iterator>; - typedef typename __gnu_cxx::__conditional_type<_IsConstant::__value, - typename _Sequence::_Base::local_iterator, - typename _Sequence::_Base::const_local_iterator>::__type - _OtherIterator; + using _OtherIterator = std::__conditional_t< + _IsConstant::__value, + typename _UContainer::_Base::local_iterator, + typename _UContainer::_Base::const_local_iterator>; typedef _Safe_local_iterator _Self; - typedef _Safe_local_iterator<_OtherIterator, _Sequence> _OtherSelf; + typedef _Safe_local_iterator<_OtherIterator, _UContainer> _OtherSelf; struct _Unchecked { }; _Safe_local_iterator(const _Safe_local_iterator& __x, _Unchecked) noexcept : _Iter_base(__x.base()) - { _M_attach(__x._M_sequence); } + { _M_attach(__x._M_safe_container()); } public: typedef _Iterator iterator_type; @@ -104,12 +103,13 @@ namespace __gnu_debug /** * @brief Safe iterator construction from an unsafe iterator and - * its sequence. + * its unordered container. * - * @pre @p seq is not NULL + * @pre @p cont is not NULL * @post this is not singular */ - _Safe_local_iterator(_Iterator __i, const _Safe_sequence_base* __cont) + _Safe_local_iterator(_Iterator __i, + const _Safe_unordered_container_base* __cont) : _Iter_base(__i), _Safe_base(__cont, _S_constant()) { } @@ -126,7 +126,7 @@ namespace __gnu_debug _M_message(__msg_init_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); - _M_attach(__x._M_sequence); + _M_attach(__x._M_safe_container()); } /** @@ -141,7 +141,7 @@ namespace __gnu_debug _M_message(__msg_init_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); - auto __cont = __x._M_sequence; + auto __cont = __x._M_safe_container(); __x._M_detach(); std::swap(base(), __x.base()); _M_attach(__cont); @@ -156,7 +156,7 @@ namespace __gnu_debug const _Safe_local_iterator<_MutableIterator, typename __gnu_cxx::__enable_if<_IsConstant::__value && std::__are_same<_MutableIterator, _OtherIterator>::__value, - _Sequence>::__type>& __x) noexcept + _UContainer>::__type>& __x) noexcept : _Iter_base(__x.base()) { // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -166,7 +166,7 @@ namespace __gnu_debug _M_message(__msg_init_const_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); - _M_attach(__x._M_sequence); + _M_attach(__x._M_safe_container()); } /** @@ -193,7 +193,7 @@ namespace __gnu_debug { _M_detach(); base() = __x.base(); - _M_attach(__x._M_sequence); + _M_attach(__x._M_safe_container()); } return *this; @@ -225,7 +225,7 @@ namespace __gnu_debug { _M_detach(); base() = __x.base(); - _M_attach(__x._M_sequence); + _M_attach(__x._M_safe_container()); } __x._M_detach(); @@ -318,15 +318,15 @@ namespace __gnu_debug */ operator _Iterator() const { return *this; } - /** Attach iterator to the given sequence. */ + /** Attach iterator to the given unordered container. */ void - _M_attach(_Safe_sequence_base* __seq) - { _Safe_base::_M_attach(__seq, _S_constant()); } + _M_attach(const _Safe_unordered_container_base* __cont) + { _Safe_base::_M_attach(__cont, _S_constant()); } /** Likewise, but not thread-safe. */ void - _M_attach_single(_Safe_sequence_base* __seq) - { _Safe_base::_M_attach_single(__seq, _S_constant()); } + _M_attach_single(const _Safe_unordered_container_base* __cont) + { _Safe_base::_M_attach_single(__cont, _S_constant()); } /// Is the iterator dereferenceable? bool @@ -353,25 +353,31 @@ namespace __gnu_debug typename _Distance_traits<_Iterator>::__type _M_get_distance_to(const _Safe_local_iterator& __rhs) const; - // The sequence this iterator references. - typename __gnu_cxx::__conditional_type< - _IsConstant::__value, const _Sequence*, _Sequence*>::__type - _M_get_sequence() const - { return static_cast<_Sequence*>(_M_sequence); } + // The unordered container this iterator references. + std::__conditional_t< + _IsConstant::__value, const _UContainer*, _UContainer*> + _M_get_ucontainer() const + { + // Looks like not const-correct, but if _IsConstant the constness + // is restored when returning the container pointer and if not + // _IsConstant we are allowed to remove constness. + return static_cast<_UContainer*> + (const_cast<_Safe_unordered_container_base*>(_M_safe_container())); + } - /// Is this iterator equal to the sequence's begin(bucket) iterator? + /// Is this iterator equal to the container's begin(bucket) iterator? bool _M_is_begin() const - { return base() == _M_get_sequence()->_M_base().begin(bucket()); } + { return base() == _M_get_ucontainer()->_M_base().begin(bucket()); } - /// Is this iterator equal to the sequence's end(bucket) iterator? + /// Is this iterator equal to the container's end(bucket) iterator? bool _M_is_end() const - { return base() == _M_get_sequence()->_M_base().end(bucket()); } + { return base() == _M_get_ucontainer()->_M_base().end(bucket()); } /// Is this iterator part of the same bucket as the other one? template<typename _Other> bool _M_in_same_bucket(const _Safe_local_iterator<_Other, - _Sequence>& __other) const + _UContainer>& __other) const { return bucket() == __other.bucket(); } friend inline bool @@ -404,31 +410,31 @@ namespace __gnu_debug }; /** Safe local iterators know how to check if they form a valid range. */ - template<typename _Iterator, typename _Sequence> + template<typename _Iterator, typename _UContainer> inline bool - __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first, - const _Safe_local_iterator<_Iterator, _Sequence>& __last, + __valid_range(const _Safe_local_iterator<_Iterator, _UContainer>& __first, + const _Safe_local_iterator<_Iterator, _UContainer>& __last, typename _Distance_traits<_Iterator>::__type& __dist_info) { return __first._M_valid_range(__last, __dist_info); } - template<typename _Iterator, typename _Sequence> + template<typename _Iterator, typename _UContainer> inline bool - __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first, - const _Safe_local_iterator<_Iterator, _Sequence>& __last) + __valid_range(const _Safe_local_iterator<_Iterator, _UContainer>& __first, + const _Safe_local_iterator<_Iterator, _UContainer>& __last) { typename _Distance_traits<_Iterator>::__type __dist_info; return __first._M_valid_range(__last, __dist_info); } #if __cplusplus < 201103L - template<typename _Iterator, typename _Sequence> - struct _Unsafe_type<_Safe_local_iterator<_Iterator, _Sequence> > + template<typename _Iterator, typename _UContainer> + struct _Unsafe_type<_Safe_local_iterator<_Iterator, _UContainer> > { typedef _Iterator _Type; }; #endif - template<typename _Iterator, typename _Sequence> + template<typename _Iterator, typename _UContainer> inline _Iterator - __unsafe(const _Safe_local_iterator<_Iterator, _Sequence>& __it) + __unsafe(const _Safe_local_iterator<_Iterator, _UContainer>& __it) { return __it.base(); } } // namespace __gnu_debug diff --git a/libstdc++-v3/include/debug/safe_local_iterator.tcc b/libstdc++-v3/include/debug/safe_local_iterator.tcc index 71e5320..10fec3f 100644 --- a/libstdc++-v3/include/debug/safe_local_iterator.tcc +++ b/libstdc++-v3/include/debug/safe_local_iterator.tcc @@ -44,7 +44,7 @@ namespace __gnu_debug if (__rhs._M_is_end()) return { - _M_get_sequence()->bucket_size(bucket()), + _M_get_ucontainer()->bucket_size(bucket()), __dp_exact }; @@ -56,7 +56,7 @@ namespace __gnu_debug if (__rhs._M_is_begin()) return { - -_M_get_sequence()->bucket_size(bucket()), + -_M_get_ucontainer()->bucket_size(bucket()), __dp_exact }; diff --git a/libstdc++-v3/include/debug/safe_sequence.h b/libstdc++-v3/include/debug/safe_sequence.h index 6b35afa..e10474a 100644 --- a/libstdc++-v3/include/debug/safe_sequence.h +++ b/libstdc++-v3/include/debug/safe_sequence.h @@ -114,7 +114,7 @@ namespace __gnu_debug in the safe ones. */ template<typename _Predicate> void - _M_invalidate_if(_Predicate __pred); + _M_invalidate_if(_Predicate __pred) const; /** Transfers all iterators @c x that reference @c from sequence, are not singular, and for which @c __pred(x) returns @c @@ -122,7 +122,8 @@ namespace __gnu_debug in the safe ones. */ template<typename _Predicate> void - _M_transfer_from_if(_Safe_sequence& __from, _Predicate __pred); + _M_transfer_from_if(const _Safe_sequence& __from, + _Predicate __pred) const; }; /// Like _Safe_sequence but with a special _M_invalidate_all implementation @@ -133,12 +134,12 @@ namespace __gnu_debug { protected: void - _M_invalidate_all() + _M_invalidate_all() const { typedef typename _Sequence::const_iterator _Const_iterator; typedef typename _Const_iterator::iterator_type _Base_const_iterator; typedef __gnu_debug::_Not_equal_to<_Base_const_iterator> _Not_equal; - const _Sequence& __seq = *static_cast<_Sequence*>(this); + const _Sequence& __seq = *static_cast<const _Sequence*>(this); this->_M_invalidate_if(_Not_equal(__seq._M_base().end())); } }; diff --git a/libstdc++-v3/include/debug/safe_sequence.tcc b/libstdc++-v3/include/debug/safe_sequence.tcc index 336bf2a..053361d 100644 --- a/libstdc++-v3/include/debug/safe_sequence.tcc +++ b/libstdc++-v3/include/debug/safe_sequence.tcc @@ -35,7 +35,7 @@ namespace __gnu_debug template<typename _Predicate> void _Safe_sequence<_Sequence>:: - _M_invalidate_if(_Predicate __pred) + _M_invalidate_if(_Predicate __pred) const { typedef typename _Sequence::iterator iterator; typedef typename _Sequence::const_iterator const_iterator; @@ -66,7 +66,7 @@ namespace __gnu_debug template<typename _Predicate> void _Safe_sequence<_Sequence>:: - _M_transfer_from_if(_Safe_sequence& __from, _Predicate __pred) + _M_transfer_from_if(const _Safe_sequence& __from, _Predicate __pred) const { if (this == std::__addressof(__from)) return; @@ -104,7 +104,7 @@ namespace __gnu_debug } for (_Safe_iterator_base* __iter2 = __from._M_const_iterators; - __iter2;) + __iter2;) { _Safe_iterator_base* __victim_base = __iter2; const_iterator* __victim = diff --git a/libstdc++-v3/include/debug/safe_unordered_base.h b/libstdc++-v3/include/debug/safe_unordered_base.h index 1547f5b..55cf581 100644 --- a/libstdc++-v3/include/debug/safe_unordered_base.h +++ b/libstdc++-v3/include/debug/safe_unordered_base.h @@ -49,6 +49,10 @@ namespace __gnu_debug */ class _Safe_local_iterator_base : public _Safe_iterator_base { + public: + const _Safe_unordered_container_base* + _M_safe_container() const noexcept; + protected: /** Initializes the iterator and makes it singular. */ _Safe_local_iterator_base() @@ -61,32 +65,32 @@ namespace __gnu_debug * singular. Otherwise, the iterator will reference @p __seq and * be nonsingular. */ - _Safe_local_iterator_base(const _Safe_sequence_base* __seq, bool __constant) - { this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); } + _Safe_local_iterator_base(const _Safe_unordered_container_base* __seq, + bool __constant) + { _M_attach(__seq, __constant); } /** Initializes the iterator to reference the same container that @p __x does. @p __constant is true if this is a constant iterator, and false if it is mutable. */ _Safe_local_iterator_base(const _Safe_local_iterator_base& __x, bool __constant) - { this->_M_attach(__x._M_sequence, __constant); } + { this->_M_attach(__x._M_safe_container(), __constant); } ~_Safe_local_iterator_base() { this->_M_detach(); } - _Safe_unordered_container_base* - _M_get_container() const noexcept; - /** Attaches this iterator to the given container, detaching it * from whatever container it was attached to originally. If the * new container is the NULL pointer, the iterator is left * unattached. */ void - _M_attach(_Safe_sequence_base* __seq, bool __constant); + _M_attach(const _Safe_unordered_container_base* __cont, + bool __constant); /** Likewise, but not thread-safe. */ void - _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw (); + _M_attach_single(const _Safe_unordered_container_base* __cont, + bool __constant) noexcept; /** Detach the iterator for whatever container it is attached to, * if any. @@ -96,7 +100,19 @@ namespace __gnu_debug /** Likewise, but not thread-safe. */ void - _M_detach_single() throw (); + _M_detach_single() noexcept; + +#if !_GLIBCXX_INLINE_VERSION + private: + /***************************************************************/ + /** Not-const method preserved for abi backward compatibility. */ + void + _M_attach(_Safe_sequence_base* __seq, bool __constant); + + void + _M_attach_single(_Safe_sequence_base* __seq, bool __constant) noexcept; + /***************************************************************/ +#endif }; /** @@ -124,10 +140,10 @@ namespace __gnu_debug public: /// The list of mutable local iterators that reference this container - _Safe_iterator_base* _M_local_iterators; + mutable _Safe_iterator_base* _M_local_iterators; /// The list of constant local iterators that reference this container - _Safe_iterator_base* _M_const_local_iterators; + mutable _Safe_iterator_base* _M_const_local_iterators; protected: // Initialize with a version number of 1 and no iterators @@ -153,7 +169,7 @@ namespace __gnu_debug /** Detach all iterators, leaving them singular. */ void - _M_detach_all(); + _M_detach_all() const; /** Swap this container with the given container. This operation * also swaps ownership of the iterators, so that when the @@ -161,25 +177,42 @@ namespace __gnu_debug * one container now reference the other container. */ void - _M_swap(_Safe_unordered_container_base& __x) noexcept; + _M_swap(const _Safe_unordered_container_base& __x) const noexcept; private: +#if !_GLIBCXX_INLINE_VERSION + /***************************************************************/ + /** Not-const method preserved for abi backward compatibility. */ + void + _M_detach_all(); + + void + _M_swap(_Safe_unordered_container_base& __x) noexcept; + /***************************************************************/ +#endif + /** Attach an iterator to this container. */ void - _M_attach_local(_Safe_iterator_base* __it, bool __constant); + _M_attach_local(_Safe_iterator_base* __it, bool __constant) const; /** Likewise but not thread safe. */ void - _M_attach_local_single(_Safe_iterator_base* __it, bool __constant) throw (); + _M_attach_local_single(_Safe_iterator_base* __it, + bool __constant) const noexcept; /** Detach an iterator from this container */ void - _M_detach_local(_Safe_iterator_base* __it); + _M_detach_local(_Safe_iterator_base* __it) const; /** Likewise but not thread safe. */ void - _M_detach_local_single(_Safe_iterator_base* __it) throw (); + _M_detach_local_single(_Safe_iterator_base* __it) const noexcept; }; + + inline const _Safe_unordered_container_base* + _Safe_local_iterator_base:: + _M_safe_container() const noexcept + { return static_cast<const _Safe_unordered_container_base*>(_M_sequence); } } // namespace __gnu_debug #endif diff --git a/libstdc++-v3/include/debug/safe_unordered_container.h b/libstdc++-v3/include/debug/safe_unordered_container.h index 2ba27db..b67b7e0 100644 --- a/libstdc++-v3/include/debug/safe_unordered_container.h +++ b/libstdc++-v3/include/debug/safe_unordered_container.h @@ -62,6 +62,10 @@ namespace __gnu_debug _M_cont() noexcept { return *static_cast<_Container*>(this); } + const _Safe_unordered_container* + _M_self() const + { return this; } + protected: void _M_invalidate_locals() diff --git a/libstdc++-v3/include/debug/safe_unordered_container.tcc b/libstdc++-v3/include/debug/safe_unordered_container.tcc index 6819389..0732e63 100644 --- a/libstdc++-v3/include/debug/safe_unordered_container.tcc +++ b/libstdc++-v3/include/debug/safe_unordered_container.tcc @@ -40,7 +40,7 @@ namespace __gnu_debug typedef typename _Container::iterator iterator; typedef typename _Container::const_iterator const_iterator; - __gnu_cxx::__scoped_lock sentry(this->_M_get_mutex()); + __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex()); for (_Safe_iterator_base* __iter = _M_iterators; __iter;) { iterator* __victim = static_cast<iterator*>(__iter); @@ -72,7 +72,7 @@ namespace __gnu_debug typedef typename _Container::local_iterator local_iterator; typedef typename _Container::const_local_iterator const_local_iterator; - __gnu_cxx::__scoped_lock sentry(this->_M_get_mutex()); + __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex()); for (_Safe_iterator_base* __iter = _M_local_iterators; __iter;) { local_iterator* __victim = static_cast<local_iterator*>(__iter); diff --git a/libstdc++-v3/include/debug/unordered_map b/libstdc++-v3/include/debug/unordered_map index 448f681..7673db1 100644 --- a/libstdc++-v3/include/debug/unordered_map +++ b/libstdc++-v3/include/debug/unordered_map @@ -175,6 +175,12 @@ namespace __debug template<typename _InputIterator> unordered_map(_InputIterator __first, _InputIterator __last, + const allocator_type& __a) + : unordered_map(__first, __last, 0, hasher(), key_equal(), __a) + { } + + template<typename _InputIterator> + unordered_map(_InputIterator __first, _InputIterator __last, size_type __n, const allocator_type& __a) : unordered_map(__first, __last, __n, hasher(), key_equal(), __a) @@ -189,6 +195,11 @@ namespace __debug { } unordered_map(initializer_list<value_type> __l, + const allocator_type& __a) + : unordered_map(__l, 0, hasher(), key_equal(), __a) + { } + + unordered_map(initializer_list<value_type> __l, size_type __n, const allocator_type& __a) : unordered_map(__l, __n, hasher(), key_equal(), __a) @@ -1053,6 +1064,12 @@ namespace __debug template<typename _InputIterator> unordered_multimap(_InputIterator __first, _InputIterator __last, + const allocator_type& __a) + : unordered_multimap(__first, __last, 0, hasher(), key_equal(), __a) + { } + + template<typename _InputIterator> + unordered_multimap(_InputIterator __first, _InputIterator __last, size_type __n, const allocator_type& __a) : unordered_multimap(__first, __last, __n, hasher(), key_equal(), __a) @@ -1066,6 +1083,11 @@ namespace __debug { } unordered_multimap(initializer_list<value_type> __l, + const allocator_type& __a) + : unordered_multimap(__l, 0, hasher(), key_equal(), __a) + { } + + unordered_multimap(initializer_list<value_type> __l, size_type __n, const allocator_type& __a) : unordered_multimap(__l, __n, hasher(), key_equal(), __a) diff --git a/libstdc++-v3/include/debug/unordered_set b/libstdc++-v3/include/debug/unordered_set index 4255f6e..932600d 100644 --- a/libstdc++-v3/include/debug/unordered_set +++ b/libstdc++-v3/include/debug/unordered_set @@ -170,6 +170,12 @@ namespace __debug template<typename _InputIterator> unordered_set(_InputIterator __first, _InputIterator __last, + const allocator_type& __a) + : unordered_set(__first, __last, 0, hasher(), key_equal(), __a) + { } + + template<typename _InputIterator> + unordered_set(_InputIterator __first, _InputIterator __last, size_type __n, const allocator_type& __a) : unordered_set(__first, __last, __n, hasher(), key_equal(), __a) @@ -183,6 +189,11 @@ namespace __debug { } unordered_set(initializer_list<value_type> __l, + const allocator_type& __a) + : unordered_set(__l, 0, hasher(), key_equal(), __a) + { } + + unordered_set(initializer_list<value_type> __l, size_type __n, const allocator_type& __a) : unordered_set(__l, __n, hasher(), key_equal(), __a) @@ -713,6 +724,17 @@ namespace __debug typename iterator_traits<_InputIterator>::value_type>, _Allocator>; + template<typename _InputIterator, typename _Allocator, + typename = _RequireInputIter<_InputIterator>, + typename = _RequireAllocator<_Allocator>> + unordered_set(_InputIterator, _InputIterator, _Allocator) + -> unordered_set<typename iterator_traits<_InputIterator>::value_type, + hash< + typename iterator_traits<_InputIterator>::value_type>, + equal_to< + typename iterator_traits<_InputIterator>::value_type>, + _Allocator>; + template<typename _InputIterator, typename _Hash, typename _Allocator, typename = _RequireInputIter<_InputIterator>, typename = _RequireNotAllocatorOrIntegral<_Hash>, @@ -732,6 +754,11 @@ namespace __debug unordered_set<int>::size_type, _Allocator) -> unordered_set<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; + template<typename _Tp, typename _Allocator, + typename = _RequireAllocator<_Allocator>> + unordered_set(initializer_list<_Tp>, _Allocator) + -> unordered_set<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; + template<typename _Tp, typename _Hash, typename _Allocator, typename = _RequireNotAllocatorOrIntegral<_Hash>, typename = _RequireAllocator<_Allocator>> @@ -878,6 +905,12 @@ namespace __debug template<typename _InputIterator> unordered_multiset(_InputIterator __first, _InputIterator __last, + const allocator_type& __a) + : unordered_multiset(__first, __last, 0, hasher(), key_equal(), __a) + { } + + template<typename _InputIterator> + unordered_multiset(_InputIterator __first, _InputIterator __last, size_type __n, const allocator_type& __a) : unordered_multiset(__first, __last, __n, hasher(), key_equal(), __a) @@ -891,6 +924,11 @@ namespace __debug { } unordered_multiset(initializer_list<value_type> __l, + const allocator_type& __a) + : unordered_multiset(__l, 0, hasher(), key_equal(), __a) + { } + + unordered_multiset(initializer_list<value_type> __l, size_type __n, const allocator_type& __a) : unordered_multiset(__l, __n, hasher(), key_equal(), __a) @@ -1416,6 +1454,17 @@ namespace __debug iterator_traits<_InputIterator>::value_type>, _Allocator>; + template<typename _InputIterator, typename _Allocator, + typename = _RequireInputIter<_InputIterator>, + typename = _RequireAllocator<_Allocator>> + unordered_multiset(_InputIterator, _InputIterator, _Allocator) + -> unordered_multiset<typename iterator_traits<_InputIterator>::value_type, + hash<typename + iterator_traits<_InputIterator>::value_type>, + equal_to<typename + iterator_traits<_InputIterator>::value_type>, + _Allocator>; + template<typename _InputIterator, typename _Hash, typename _Allocator, typename = _RequireInputIter<_InputIterator>, typename = _RequireNotAllocatorOrIntegral<_Hash>, @@ -1437,6 +1486,11 @@ namespace __debug unordered_multiset<int>::size_type, _Allocator) -> unordered_multiset<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; + template<typename _Tp, typename _Allocator, + typename = _RequireAllocator<_Allocator>> + unordered_multiset(initializer_list<_Tp>, _Allocator) + -> unordered_multiset<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; + template<typename _Tp, typename _Hash, typename _Allocator, typename = _RequireNotAllocatorOrIntegral<_Hash>, typename = _RequireAllocator<_Allocator>> diff --git a/libstdc++-v3/include/experimental/memory b/libstdc++-v3/include/experimental/memory index 131e5ac..1b01462 100644 --- a/libstdc++-v3/include/experimental/memory +++ b/libstdc++-v3/include/experimental/memory @@ -148,42 +148,42 @@ inline namespace fundamentals_v2 }; // observer_ptr<> template<typename _Tp> - void + constexpr void swap(observer_ptr<_Tp>& __p1, observer_ptr<_Tp>& __p2) noexcept { __p1.swap(__p2); } template<typename _Tp> - observer_ptr<_Tp> + constexpr observer_ptr<_Tp> make_observer(_Tp* __p) noexcept { return observer_ptr<_Tp>(__p); } template<typename _Tp, typename _Up> - bool + constexpr bool operator==(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) { return __p1.get() == __p2.get(); } template<typename _Tp, typename _Up> - bool + constexpr bool operator!=(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) { return !(__p1 == __p2); } template<typename _Tp> - bool + constexpr bool operator==(observer_ptr<_Tp> __p, nullptr_t) noexcept { return !__p; } template<typename _Tp> - bool + constexpr bool operator==(nullptr_t, observer_ptr<_Tp> __p) noexcept { return !__p; @@ -197,14 +197,14 @@ inline namespace fundamentals_v2 } template<typename _Tp> - bool + constexpr bool operator!=(nullptr_t, observer_ptr<_Tp> __p) noexcept { return bool(__p); } template<typename _Tp, typename _Up> - bool + constexpr bool operator<(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) { return std::less<typename common_type<typename add_pointer<_Tp>::type, @@ -214,21 +214,21 @@ inline namespace fundamentals_v2 } template<typename _Tp, typename _Up> - bool + constexpr bool operator>(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) { return __p2 < __p1; } template<typename _Tp, typename _Up> - bool + constexpr bool operator<=(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) { return !(__p2 < __p1); } template<typename _Tp, typename _Up> - bool + constexpr bool operator>=(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) { return !(__p1 < __p2); diff --git a/libstdc++-v3/include/experimental/numeric b/libstdc++-v3/include/experimental/numeric index 381ecf3..33e9731 100644 --- a/libstdc++-v3/include/experimental/numeric +++ b/libstdc++-v3/include/experimental/numeric @@ -88,9 +88,12 @@ inline namespace fundamentals_v2 return 0; _Ct __r = __m2 / __detail::__gcd<make_unsigned_t<_Ct>>(__m2, __n2); - if _GLIBCXX17_CONSTEXPR (is_signed_v<_Ct>) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + if constexpr (is_signed_v<_Ct>) if (__is_constant_evaluated()) return __r * __n2; // constant evaluation can detect overflow here. +#pragma GCC diagnostic pop bool __overflow = __builtin_mul_overflow(__r, __n2, &__r); __glibcxx_assert(!__overflow); diff --git a/libstdc++-v3/include/ext/atomicity.h b/libstdc++-v3/include/ext/atomicity.h index 98f745c..0b970f3 100644 --- a/libstdc++-v3/include/ext/atomicity.h +++ b/libstdc++-v3/include/ext/atomicity.h @@ -39,6 +39,9 @@ #if __has_include(<sys/single_threaded.h>) # include <sys/single_threaded.h> #endif +#if __cplusplus >= 201103L +# include <type_traits> // make_unsigned_t +#endif namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) { @@ -61,7 +64,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // To abstract locking primitives across all thread policies, use: // __exchange_and_add_dispatch // __atomic_add_dispatch -#ifdef _GLIBCXX_ATOMIC_BUILTINS +#ifdef _GLIBCXX_ATOMIC_WORD_BUILTINS inline _Atomic_word __attribute__((__always_inline__)) __exchange_and_add(volatile _Atomic_word* __mem, int __val) @@ -71,7 +74,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __attribute__((__always_inline__)) __atomic_add(volatile _Atomic_word* __mem, int __val) { __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); } -#else +#else // Defined in config/cpu/.../atomicity.h _Atomic_word __exchange_and_add(volatile _Atomic_word*, int) _GLIBCXX_NOTHROW; @@ -79,19 +82,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __atomic_add(volatile _Atomic_word*, int) _GLIBCXX_NOTHROW; #endif +#if __cplusplus < 201103L + // The array bound will be ill-formed in the very unlikely case that + // _Atomic_word is wider than long and we need to use unsigned long long + // below in __exchange_and_add_single and __atomic_add_single. + typedef int + _Atomic_word_fits_in_long[sizeof(_Atomic_word) <= sizeof(long) ? 1 : -1]; +#endif + inline _Atomic_word __attribute__((__always_inline__)) __exchange_and_add_single(_Atomic_word* __mem, int __val) { _Atomic_word __result = *__mem; - *__mem += __val; + // Do the addition with an unsigned type so that overflow is well defined. +#if __cplusplus >= 201103L + std::make_unsigned<_Atomic_word>::type __u; +#else + // For most targets make_unsigned_t<_Atomic_word> is unsigned int, + // but 64-bit sparc uses long for _Atomic_word. + // Sign-extending to unsigned long works for both cases. + unsigned long __u; +#endif + __u = __result; + __u += __val; + *__mem = __u; return __result; } inline void __attribute__((__always_inline__)) __atomic_add_single(_Atomic_word* __mem, int __val) - { *__mem += __val; } + { +#if __cplusplus >= 201103L + std::make_unsigned<_Atomic_word>::type __u; +#else + unsigned long __u; // see above +#endif + __u = *__mem; + __u += __val; + *__mem = __u; + } inline _Atomic_word __attribute__ ((__always_inline__)) diff --git a/libstdc++-v3/include/ext/numeric_traits.h b/libstdc++-v3/include/ext/numeric_traits.h index 2cd8943..6786dc6 100644 --- a/libstdc++-v3/include/ext/numeric_traits.h +++ b/libstdc++-v3/include/ext/numeric_traits.h @@ -126,12 +126,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_INT_N_TRAITS(__GLIBCXX_TYPE_INT_N_3, __GLIBCXX_BITSIZE_INT_N_3) #endif -#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ - // In strict modes __is_integer<__int128> is false, - // but we still want to define __numeric_traits_integer<__int128>. - _GLIBCXX_INT_N_TRAITS(__int128, 128) -#endif - #undef _GLIBCXX_INT_N_TRAITS #if __cplusplus >= 201103L diff --git a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp index 6088709..a8c73b5 100644 --- a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp +++ b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp @@ -305,6 +305,9 @@ namespace __gnu_pbds rotate_parent(node_pointer); inline void + update_subtree_size(node_pointer); + + inline void apply_update(node_pointer, null_node_update_pointer); template<typename Node_Update_> diff --git a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp index e6e954d..b8f5014 100644 --- a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp +++ b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp @@ -122,7 +122,6 @@ insert_leaf_new(const_reference r_value, node_pointer p_nd, bool left_nd) } p_new_nd->m_p_parent = p_nd; - p_new_nd->m_p_left = p_new_nd->m_p_right = 0; PB_DS_ASSERT_NODE_CONSISTENT(p_nd) update_to_top(p_new_nd, (node_update* )this); @@ -142,7 +141,6 @@ insert_imp_empty(const_reference r_value) m_p_head->m_p_parent = p_new_node; p_new_node->m_p_parent = m_p_head; - p_new_node->m_p_left = p_new_node->m_p_right = 0; _GLIBCXX_DEBUG_ONLY(debug_base::insert_new(PB_DS_V2F(r_value));) update_to_top(m_p_head->m_p_parent, (node_update*)this); diff --git a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp index 069b17f..8cadce2 100644 --- a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp +++ b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp @@ -122,8 +122,23 @@ rotate_parent(node_pointer p_nd) PB_DS_CLASS_T_DEC inline void PB_DS_CLASS_C_DEC:: -apply_update(node_pointer /*p_nd*/, null_node_update_pointer /*p_update*/) -{ } +update_subtree_size(node_pointer p_nd) +{ + size_type size = 1; + if (p_nd->m_p_left) + size += p_nd->m_p_left->m_subtree_size; + if (p_nd->m_p_right) + size += p_nd->m_p_right->m_subtree_size; + p_nd->m_subtree_size = size; +} + +PB_DS_CLASS_T_DEC +inline void +PB_DS_CLASS_C_DEC:: +apply_update(node_pointer p_nd, null_node_update_pointer /*p_update*/) +{ + update_subtree_size(p_nd); +} PB_DS_CLASS_T_DEC template<typename Node_Update_> @@ -131,6 +146,7 @@ inline void PB_DS_CLASS_C_DEC:: apply_update(node_pointer p_nd, Node_Update_* /*p_update*/) { + update_subtree_size(p_nd); node_update::operator()(node_iterator(p_nd), node_const_iterator(static_cast<node_pointer>(0))); } @@ -152,7 +168,14 @@ update_to_top(node_pointer p_nd, Node_Update_* p_update) PB_DS_CLASS_T_DEC inline void PB_DS_CLASS_C_DEC:: -update_to_top(node_pointer /*p_nd*/, null_node_update_pointer /*p_update*/) -{ } +update_to_top(node_pointer p_nd, null_node_update_pointer /*p_update */) +{ + while (p_nd != m_p_head) + { + update_subtree_size(p_nd); + + p_nd = p_nd->m_p_parent; + } +} #endif diff --git a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp index 0c1b26f..a2a5775 100644 --- a/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp +++ b/libstdc++-v3/include/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp @@ -133,7 +133,9 @@ PB_DS_CLASS_C_DEC:: split_finish(PB_DS_CLASS_C_DEC& other) { other.initialize_min_max(); - other.m_size = std::distance(other.begin(), other.end()); + other.m_size = 0; + if (other.m_p_head->m_p_parent != 0) + other.m_size = other.m_p_head->m_p_parent->m_subtree_size; m_size -= other.m_size; initialize_min_max(); PB_DS_ASSERT_VALID((*this)) diff --git a/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/node.hpp b/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/node.hpp index f229be7..3803ddb 100644 --- a/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/node.hpp +++ b/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/node.hpp @@ -58,6 +58,9 @@ namespace __gnu_pbds typedef typename rebind_traits<_Alloc, rb_tree_node_>::pointer node_pointer; + typedef typename rebind_traits<_Alloc, rb_tree_node_>::size_type + size_type; + typedef typename rebind_traits<_Alloc, metadata_type>::reference metadata_reference; @@ -88,6 +91,7 @@ namespace __gnu_pbds node_pointer m_p_left; node_pointer m_p_right; node_pointer m_p_parent; + size_type m_subtree_size; value_type m_value; bool m_red; metadata_type m_metadata; @@ -100,6 +104,9 @@ namespace __gnu_pbds typedef Value_Type value_type; typedef null_type metadata_type; + typedef typename rebind_traits<_Alloc, rb_tree_node_>::size_type + size_type; + typedef typename rebind_traits<_Alloc, rb_tree_node_>::pointer node_pointer; @@ -116,6 +123,7 @@ namespace __gnu_pbds node_pointer m_p_left; node_pointer m_p_right; node_pointer m_p_parent; + size_type m_subtree_size; value_type m_value; bool m_red; }; diff --git a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/node.hpp b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/node.hpp index 961afbe..b5fbb50 100644 --- a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/node.hpp +++ b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/node.hpp @@ -56,6 +56,9 @@ namespace __gnu_pbds typedef typename rebind_traits<_Alloc, splay_tree_node_>::pointer node_pointer; + typedef typename rebind_traits<_Alloc, splay_tree_node_>::size_type + size_type; + typedef typename rebind_traits<_Alloc, metadata_type>::reference metadata_reference; @@ -85,6 +88,7 @@ namespace __gnu_pbds node_pointer m_p_left; node_pointer m_p_right; node_pointer m_p_parent; + size_type m_subtree_size; metadata_type m_metadata; }; @@ -98,6 +102,9 @@ namespace __gnu_pbds typedef typename rebind_traits<_Alloc, splay_tree_node_>::pointer node_pointer; + typedef typename rebind_traits<_Alloc, splay_tree_node_>::size_type + size_type; + inline bool special() const { return m_special; } @@ -111,6 +118,7 @@ namespace __gnu_pbds node_pointer m_p_left; node_pointer m_p_right; node_pointer m_p_parent; + size_type m_subtree_size; value_type m_value; bool m_special; }; diff --git a/libstdc++-v3/include/ext/pointer.h b/libstdc++-v3/include/ext/pointer.h index 700c9a1..5feb9f0 100644 --- a/libstdc++-v3/include/ext/pointer.h +++ b/libstdc++-v3/include/ext/pointer.h @@ -40,6 +40,7 @@ #pragma GCC system_header #endif +#include <bits/c++config.h> #if _GLIBCXX_HOSTED # include <iosfwd> #endif diff --git a/libstdc++-v3/include/precompiled/extc++.h b/libstdc++-v3/include/precompiled/extc++.h index cc6e5e5..9d41656 100644 --- a/libstdc++-v3/include/precompiled/extc++.h +++ b/libstdc++-v3/include/precompiled/extc++.h @@ -37,7 +37,6 @@ #endif #include <ext/alloc_traits.h> #include <ext/atomicity.h> -#include <ext/cast.h> #include <ext/iterator> #include <ext/numeric_traits.h> #include <ext/pointer.h> diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h index f4b312d..636632a 100644 --- a/libstdc++-v3/include/precompiled/stdc++.h +++ b/libstdc++-v3/include/precompiled/stdc++.h @@ -228,6 +228,7 @@ #include <flat_map> #include <flat_set> #include <generator> +#include <mdspan> #include <print> #include <spanstream> #include <stacktrace> @@ -236,6 +237,8 @@ #endif #if __cplusplus > 202302L +#include <debugging> +#include <inplace_vector> #include <text_encoding> #include <stdbit.h> #include <stdckdint.h> diff --git a/libstdc++-v3/include/pstl/algorithm_impl.h b/libstdc++-v3/include/pstl/algorithm_impl.h index 5b1cd20..2080e82 100644 --- a/libstdc++-v3/include/pstl/algorithm_impl.h +++ b/libstdc++-v3/include/pstl/algorithm_impl.h @@ -79,7 +79,7 @@ template <class _ForwardIterator, class _Size, class _Function> _ForwardIterator __for_each_n_it_serial(_ForwardIterator __first, _Size __n, _Function __f) { - for (; __n > 0; ++__first, --__n) + for (; __n > 0; ++__first, (void) --__n) __f(__first); return __first; } @@ -221,7 +221,7 @@ _ForwardIterator2 __brick_walk2(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _Function __f, /*vector=*/std::false_type) noexcept { - for (; __first1 != __last1; ++__first1, ++__first2) + for (; __first1 != __last1; ++__first1, (void) ++__first2) __f(*__first1, *__first2); return __first2; } @@ -240,7 +240,7 @@ _ForwardIterator2 __brick_walk2_n(_ForwardIterator1 __first1, _Size __n, _ForwardIterator2 __first2, _Function __f, /*vector=*/std::false_type) noexcept { - for (; __n > 0; --__n, ++__first1, ++__first2) + for (; __n > 0; --__n, (void) ++__first1, ++__first2) __f(*__first1, *__first2); return __first2; } @@ -364,7 +364,7 @@ _ForwardIterator3 __brick_walk3(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator3 __first3, _Function __f, /*vector=*/std::false_type) noexcept { - for (; __first1 != __last1; ++__first1, ++__first2, ++__first3) + for (; __first1 != __last1; ++__first1, (void) ++__first2, ++__first3) __f(*__first1, *__first2, *__first3); return __first3; } @@ -961,7 +961,7 @@ struct __brick_move_destroy { using _IteratorValueType = typename std::iterator_traits<_RandomAccessIterator1>::value_type; - for (; __first != __last; ++__first, ++__result) + for (; __first != __last; ++__first, (void) ++__result) { *__result = std::move(*__first); (*__first).~_IteratorValueType(); @@ -1027,7 +1027,7 @@ __brick_calc_mask_1(_ForwardIterator __first, _ForwardIterator __last, bool* __r static_assert(__are_random_access_iterators<_ForwardIterator>::value, "Pattern-brick error. Should be a random access iterator."); - for (; __first != __last; ++__first, ++__mask) + for (; __first != __last; ++__first, (void) ++__mask) { *__mask = __pred(*__first); if (*__mask) @@ -1052,7 +1052,7 @@ void __brick_copy_by_mask(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result, bool* __mask, _Assigner __assigner, /*vector=*/std::false_type) noexcept { - for (; __first != __last; ++__first, ++__mask) + for (; __first != __last; ++__first, (void) ++__mask) { if (*__mask) { @@ -1079,7 +1079,7 @@ void __brick_partition_by_mask(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator1 __out_true, _OutputIterator2 __out_false, bool* __mask, /*vector=*/std::false_type) noexcept { - for (; __first != __last; ++__first, ++__mask) + for (; __first != __last; ++__first, (void) ++__mask) { if (*__mask) { @@ -1383,7 +1383,7 @@ __brick_calc_mask_2(_RandomAccessIterator __first, _RandomAccessIterator __last, _BinaryPredicate __pred, /*vector=*/std::false_type) noexcept { _DifferenceType __count = 0; - for (; __first != __last; ++__first, ++__mask) + for (; __first != __last; ++__first, (void) ++__mask) { *__mask = !__pred(*__first, *(__first - 1)); __count += *__mask; @@ -1483,7 +1483,7 @@ void __brick_reverse(_BidirectionalIterator __first, _BidirectionalIterator __last, _BidirectionalIterator __d_last, /*is_vector=*/std::false_type) noexcept { - for (--__d_last; __first != __last; ++__first, --__d_last) + for (--__d_last; __first != __last; ++__first, (void) --__d_last) { using std::iter_swap; iter_swap(__first, __d_last); @@ -2333,7 +2333,7 @@ __pattern_partial_sort_copy(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& _RandomAccessIterator1 __it = __first + (__i - __r); // 1. Copy elements from input to raw memory - for (_T1* __k = __i; __k != __j; ++__k, ++__it) + for (_T1* __k = __i; __k != __j; ++__k, (void) ++__it) { ::new (__k) _T2(*__it); } @@ -3648,7 +3648,7 @@ __mismatch_serial(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _Forwar #if defined(_PSTL_CPP14_2RANGE_MISMATCH_EQUAL_PRESENT) return std::mismatch(__first1, __last1, __first2, __last2, __pred); #else - for (; __first1 != __last1 && __first2 != __last2 && __pred(*__first1, *__first2); ++__first1, ++__first2) + for (; __first1 != __last1 && __first2 != __last2 && __pred(*__first1, *__first2); ++__first1, (void) ++__first2) { } return std::make_pair(__first1, __first2); diff --git a/libstdc++-v3/include/pstl/glue_numeric_impl.h b/libstdc++-v3/include/pstl/glue_numeric_impl.h index 10d4912..fe2d0fd 100644 --- a/libstdc++-v3/include/pstl/glue_numeric_impl.h +++ b/libstdc++-v3/include/pstl/glue_numeric_impl.h @@ -25,7 +25,7 @@ __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _Tp> reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init, _BinaryOperation __binary_op) { - return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, __init, __binary_op, + return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, std::move(__init), __binary_op, __pstl::__internal::__no_op()); } @@ -33,7 +33,7 @@ template <class _ExecutionPolicy, class _ForwardIterator, class _Tp> __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _Tp> reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init) { - return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, __init, std::plus<_Tp>(), + return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, std::move(__init), std::plus<_Tp>(), __pstl::__internal::__no_op()); } @@ -58,7 +58,7 @@ transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _Forward typedef typename iterator_traits<_ForwardIterator1>::value_type _InputType; return __pstl::__internal::__pattern_transform_reduce(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec), - __first1, __last1, __first2, __init, std::plus<_InputType>(), + __first1, __last1, __first2, std::move(__init), std::plus<_InputType>(), std::multiplies<_InputType>()); } @@ -70,7 +70,7 @@ transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _Forward { auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first1, __first2); return __pstl::__internal::__pattern_transform_reduce(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec), - __first1, __last1, __first2, __init, __binary_op1, + __first1, __last1, __first2, std::move(__init), __binary_op1, __binary_op2); } @@ -81,7 +81,7 @@ transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIt { auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first); return __pstl::__internal::__pattern_transform_reduce(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec), - __first, __last, __init, __binary_op, __unary_op); + __first, __last, std::move(__init), __binary_op, __unary_op); } // [exclusive.scan] @@ -139,7 +139,7 @@ inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIte _ForwardIterator2 __result, _BinaryOperation __binary_op, _Tp __init) { return transform_inclusive_scan(std::forward<_ExecutionPolicy>(__exec), __first, __last, __result, __binary_op, - __pstl::__internal::__no_op(), __init); + __pstl::__internal::__no_op(), std::move(__init)); } // [transform.exclusive.scan] @@ -154,7 +154,7 @@ transform_exclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first, __result); return __pstl::__internal::__pattern_transform_scan(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec), __first, - __last, __result, __unary_op, __init, __binary_op, + __last, __result, __unary_op, std::move(__init), __binary_op, /*inclusive=*/std::false_type()); } @@ -170,7 +170,7 @@ transform_inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first, __result); return __pstl::__internal::__pattern_transform_scan(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec), __first, - __last, __result, __unary_op, __init, __binary_op, + __last, __result, __unary_op, std::move(__init), __binary_op, /*inclusive=*/std::true_type()); } diff --git a/libstdc++-v3/include/pstl/memory_impl.h b/libstdc++-v3/include/pstl/memory_impl.h index 8cb32d0..080b6ca 100644 --- a/libstdc++-v3/include/pstl/memory_impl.h +++ b/libstdc++-v3/include/pstl/memory_impl.h @@ -29,7 +29,7 @@ __brick_uninitialized_move(_ForwardIterator __first, _ForwardIterator __last, _O /*vector=*/std::false_type) noexcept { using _ValueType = typename std::iterator_traits<_OutputIterator>::value_type; - for (; __first != __last; ++__first, ++__result) + for (; __first != __last; ++__first, (void) ++__result) { ::new (std::addressof(*__result)) _ValueType(std::move(*__first)); } @@ -80,7 +80,7 @@ __brick_uninitialized_copy(_ForwardIterator __first, _ForwardIterator __last, _O /*vector=*/std::false_type) noexcept { using _ValueType = typename std::iterator_traits<_OutputIterator>::value_type; - for (; __first != __last; ++__first, ++__result) + for (; __first != __last; ++__first, (void) ++__result) { ::new (std::addressof(*__result)) _ValueType(*__first); } diff --git a/libstdc++-v3/include/pstl/numeric_impl.h b/libstdc++-v3/include/pstl/numeric_impl.h index e1ebec1..af6f6a2 100644 --- a/libstdc++-v3/include/pstl/numeric_impl.h +++ b/libstdc++-v3/include/pstl/numeric_impl.h @@ -35,7 +35,7 @@ __brick_transform_reduce(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _BinaryOperation1 __binary_op1, _BinaryOperation2 __binary_op2, /*is_vector=*/std::false_type) noexcept { - return std::inner_product(__first1, __last1, __first2, __init, __binary_op1, __binary_op2); + return std::inner_product(__first1, __last1, __first2, std::move(__init), __binary_op1, __binary_op2); } template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _Tp, class _BinaryOperation1, @@ -48,7 +48,7 @@ __brick_transform_reduce(_RandomAccessIterator1 __first1, _RandomAccessIterator1 { typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type _DifferenceType; return __unseq_backend::__simd_transform_reduce( - __last1 - __first1, __init, __binary_op1, + __last1 - __first1, std::move(__init), __binary_op1, [=, &__binary_op2](_DifferenceType __i) { return __binary_op2(__first1[__i], __first2[__i]); }); } @@ -59,7 +59,7 @@ __pattern_transform_reduce(_Tag, _ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator2 __first2, _Tp __init, _BinaryOperation1 __binary_op1, _BinaryOperation2 __binary_op2) noexcept { - return __brick_transform_reduce(__first1, __last1, __first2, __init, __binary_op1, __binary_op2, + return __brick_transform_reduce(__first1, __last1, __first2, std::move(__init), __binary_op1, __binary_op2, typename _Tag::__is_vector{}); } @@ -79,12 +79,12 @@ __pattern_transform_reduce(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& _ __backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __first1, __last1, [__first1, __first2, __binary_op2](_RandomAccessIterator1 __i) mutable { return __binary_op2(*__i, *(__first2 + (__i - __first1))); }, - __init, + std::move(__init), __binary_op1, // Combine [__first1, __first2, __binary_op1, __binary_op2](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j, _Tp __init) -> _Tp { - return __internal::__brick_transform_reduce(__i, __j, __first2 + (__i - __first1), __init, + return __internal::__brick_transform_reduce(__i, __j, __first2 + (__i - __first1), std::move(__init), __binary_op1, __binary_op2, _IsVector{}); }); }); @@ -99,7 +99,7 @@ _Tp __brick_transform_reduce(_ForwardIterator __first, _ForwardIterator __last, _Tp __init, _BinaryOperation __binary_op, _UnaryOperation __unary_op, /*is_vector=*/std::false_type) noexcept { - return std::transform_reduce(__first, __last, __init, __binary_op, __unary_op); + return std::transform_reduce(__first, __last, std::move(__init), __binary_op, __unary_op); } template <class _RandomAccessIterator, class _Tp, class _UnaryOperation, class _BinaryOperation> @@ -110,7 +110,7 @@ __brick_transform_reduce(_RandomAccessIterator __first, _RandomAccessIterator __ { typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _DifferenceType; return __unseq_backend::__simd_transform_reduce( - __last - __first, __init, __binary_op, + __last - __first, std::move(__init), __binary_op, [=, &__unary_op](_DifferenceType __i) { return __unary_op(__first[__i]); }); } @@ -120,7 +120,7 @@ _Tp __pattern_transform_reduce(_Tag, _ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Tp __init, _BinaryOperation __binary_op, _UnaryOperation __unary_op) noexcept { - return __internal::__brick_transform_reduce(__first, __last, __init, __binary_op, __unary_op, + return __internal::__brick_transform_reduce(__first, __last, std::move(__init), __binary_op, __unary_op, typename _Tag::__is_vector{}); } @@ -138,9 +138,9 @@ __pattern_transform_reduce(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& _ { return __par_backend::__parallel_transform_reduce( __backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __first, __last, - [__unary_op](_RandomAccessIterator __i) mutable { return __unary_op(*__i); }, __init, __binary_op, + [__unary_op](_RandomAccessIterator __i) mutable { return __unary_op(*__i); }, std::move(__init), __binary_op, [__unary_op, __binary_op](_RandomAccessIterator __i, _RandomAccessIterator __j, _Tp __init) { - return __internal::__brick_transform_reduce(__i, __j, __init, __binary_op, __unary_op, _IsVector{}); + return __internal::__brick_transform_reduce(__i, __j, std::move(__init), __binary_op, __unary_op, _IsVector{}); }); }); } @@ -158,7 +158,7 @@ __brick_transform_scan(_ForwardIterator __first, _ForwardIterator __last, _Outpu _UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op, /*Inclusive*/ std::false_type, /*is_vector=*/std::false_type) noexcept { - for (; __first != __last; ++__first, ++__result) + for (; __first != __last; ++__first, (void) ++__result) { _Tp __v = std::move(__init); _PSTL_PRAGMA_FORCEINLINE @@ -175,13 +175,13 @@ __brick_transform_scan(_RandomAccessIterator __first, _RandomAccessIterator __la _UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op, /*Inclusive*/ std::true_type, /*is_vector=*/std::false_type) noexcept { - for (; __first != __last; ++__first, ++__result) + for (; __first != __last; ++__first, (void) ++__result) { _PSTL_PRAGMA_FORCEINLINE __init = __binary_op(__init, __unary_op(*__first)); *__result = __init; } - return std::make_pair(__result, __init); + return std::make_pair(__result, std::move(__init)); } // type is arithmetic and binary operation is a user defined operation. @@ -199,11 +199,11 @@ __brick_transform_scan(_RandomAccessIterator __first, _RandomAccessIterator __la /*is_vector=*/std::true_type) noexcept { #if defined(_PSTL_UDS_PRESENT) - return __unseq_backend::__simd_scan(__first, __last - __first, __result, __unary_op, __init, __binary_op, + return __unseq_backend::__simd_scan(__first, __last - __first, __result, __unary_op, std::move(__init), __binary_op, _Inclusive()); #else // We need to call serial brick here to call function for inclusive and exclusive scan that depends on _Inclusive() value - return __internal::__brick_transform_scan(__first, __last, __result, __unary_op, __init, __binary_op, _Inclusive(), + return __internal::__brick_transform_scan(__first, __last, __result, __unary_op, std::move(__init), __binary_op, _Inclusive(), /*is_vector=*/std::false_type()); #endif } @@ -215,7 +215,7 @@ __brick_transform_scan(_RandomAccessIterator __first, _RandomAccessIterator __la _UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op, _Inclusive, /*is_vector=*/std::true_type) noexcept { - return __internal::__brick_transform_scan(__first, __last, __result, __unary_op, __init, __binary_op, _Inclusive(), + return __internal::__brick_transform_scan(__first, __last, __result, __unary_op, std::move(__init), __binary_op, _Inclusive(), /*is_vector=*/std::false_type()); } @@ -247,19 +247,19 @@ __pattern_transform_scan(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& __e { __par_backend::__parallel_transform_scan( __backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __last - __first, - [__first, __unary_op](_DifferenceType __i) mutable { return __unary_op(__first[__i]); }, __init, + [__first, __unary_op](_DifferenceType __i) mutable { return __unary_op(__first[__i]); }, std::move(__init), __binary_op, [__first, __unary_op, __binary_op](_DifferenceType __i, _DifferenceType __j, _Tp __init) { // Execute serial __brick_transform_reduce, due to the explicit SIMD vectorization (reduction) requires a commutative operation for the guarantee of correct scan. - return __internal::__brick_transform_reduce(__first + __i, __first + __j, __init, __binary_op, + return __internal::__brick_transform_reduce(__first + __i, __first + __j, std::move(__init), __binary_op, __unary_op, /*__is_vector*/ std::false_type()); }, [__first, __unary_op, __binary_op, __result](_DifferenceType __i, _DifferenceType __j, _Tp __init) { return __internal::__brick_transform_scan(__first + __i, __first + __j, __result + __i, __unary_op, - __init, __binary_op, _Inclusive(), _IsVector{}) + std::move(__init), __binary_op, _Inclusive(), _IsVector{}) .second; }); return __result + (__last - __first); @@ -286,7 +286,7 @@ __pattern_transform_scan(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& __e [&]() { __par_backend::__parallel_strict_scan( - __backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __n, __init, + __backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __n, std::move(__init), [__first, __unary_op, __binary_op, __result](_DifferenceType __i, _DifferenceType __len) { return __internal::__brick_transform_scan(__first + __i, __first + (__i + __len), __result + __i, diff --git a/libstdc++-v3/include/pstl/parallel_backend_tbb.h b/libstdc++-v3/include/pstl/parallel_backend_tbb.h index bb6fa8f..ff5236f 100644 --- a/libstdc++-v3/include/pstl/parallel_backend_tbb.h +++ b/libstdc++-v3/include/pstl/parallel_backend_tbb.h @@ -521,7 +521,7 @@ class __root_task friend class __func_task<_Func>; }; -#else // TBB_INTERFACE_VERSION <= 12000 +#else // TBB_INTERFACE_VERSION > 12000 class __task : public tbb::detail::d1::task { protected: @@ -656,10 +656,16 @@ class __func_task : public __task _PSTL_ASSERT(__parent != nullptr); _PSTL_ASSERT(__parent->_M_refcount.load(std::memory_order_relaxed) > 0); - if (--__parent->_M_refcount == 0) + + auto __refcount = --__parent->_M_refcount; + + // Placing the deallocation after the refcount decrement allows another thread to proceed with tree + // folding concurrently with this task cleanup. + __alloc.deallocate(this, *__ed); + + if (__refcount == 0) { _PSTL_ASSERT(__next == nullptr); - __alloc.deallocate(this, *__ed); return __parent; } diff --git a/libstdc++-v3/include/std/algorithm b/libstdc++-v3/include/std/algorithm index 321a5e2..1563cdf 100644 --- a/libstdc++-v3/include/std/algorithm +++ b/libstdc++-v3/include/std/algorithm @@ -74,6 +74,7 @@ #define __glibcxx_want_ranges_contains #define __glibcxx_want_ranges_find_last #define __glibcxx_want_ranges_fold +#define __glibcxx_want_ranges_starts_ends_with #define __glibcxx_want_robust_nonmodifying_seq_ops #define __glibcxx_want_sample #define __glibcxx_want_shift diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index fdcf0b0..12f0109 100644 --- a/libstdc++-v3/include/std/array +++ b/libstdc++-v3/include/std/array @@ -381,6 +381,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __one.swap(__two); } #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2766. Swapping non-swappable types template<typename _Tp, std::size_t _Nm> __enable_if_t<!__array_traits<_Tp, _Nm>::_Is_swappable::value> swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&) = delete; diff --git a/libstdc++-v3/include/std/barrier b/libstdc++-v3/include/std/barrier index 6c3cfd4..56270c9 100644 --- a/libstdc++-v3/include/std/barrier +++ b/libstdc++-v3/include/std/barrier @@ -81,105 +81,142 @@ It looks different from literature pseudocode for two main reasons: enum class __barrier_phase_t : unsigned char { }; - template<typename _CompletionF> - class __tree_barrier + struct __tree_barrier_base + { + static constexpr ptrdiff_t + max() noexcept + { return __PTRDIFF_MAX__ - 1; } + + protected: + using __atomic_phase_ref_t = std::__atomic_ref<__barrier_phase_t>; + using __atomic_phase_const_ref_t = std::__atomic_ref<const __barrier_phase_t>; + static constexpr auto __phase_alignment = + __atomic_phase_ref_t::required_alignment; + + using __tickets_t = std::array<__barrier_phase_t, 64>; + struct alignas(64) /* naturally-align the heap state */ __state_t { - using __atomic_phase_ref_t = std::__atomic_ref<__barrier_phase_t>; - using __atomic_phase_const_ref_t = std::__atomic_ref<const __barrier_phase_t>; - static constexpr auto __phase_alignment = - __atomic_phase_ref_t::required_alignment; + alignas(__phase_alignment) __tickets_t __tickets; + }; - using __tickets_t = std::array<__barrier_phase_t, 64>; - struct alignas(64) /* naturally-align the heap state */ __state_t - { - alignas(__phase_alignment) __tickets_t __tickets; - }; + ptrdiff_t _M_expected; + __atomic_base<__state_t*> _M_state{nullptr}; + __atomic_base<ptrdiff_t> _M_expected_adjustment{0}; + alignas(__phase_alignment) __barrier_phase_t _M_phase{}; - ptrdiff_t _M_expected; - unique_ptr<__state_t[]> _M_state; - __atomic_base<ptrdiff_t> _M_expected_adjustment; - _CompletionF _M_completion; + explicit constexpr + __tree_barrier_base(ptrdiff_t __expected) + : _M_expected(__expected) + { + __glibcxx_assert(__expected >= 0 && __expected <= max()); - alignas(__phase_alignment) __barrier_phase_t _M_phase; + if (!std::is_constant_evaluated()) + _M_state.store(_M_alloc_state().release(), memory_order_release); + } - bool - _M_arrive(__barrier_phase_t __old_phase, size_t __current) - { - const auto __old_phase_val = static_cast<unsigned char>(__old_phase); - const auto __half_step = - static_cast<__barrier_phase_t>(__old_phase_val + 1); - const auto __full_step = - static_cast<__barrier_phase_t>(__old_phase_val + 2); + unique_ptr<__state_t[]> + _M_alloc_state() + { + size_t const __count = (_M_expected + 1) >> 1; + return std::make_unique<__state_t[]>(__count); + } - size_t __current_expected = _M_expected; - __current %= ((_M_expected + 1) >> 1); + bool + _M_arrive(__barrier_phase_t __old_phase, size_t __current) + { + const auto __old_phase_val = static_cast<unsigned char>(__old_phase); + const auto __half_step = + static_cast<__barrier_phase_t>(__old_phase_val + 1); + const auto __full_step = + static_cast<__barrier_phase_t>(__old_phase_val + 2); + + size_t __current_expected = _M_expected; + __current %= ((_M_expected + 1) >> 1); + + __state_t* const __state = _M_state.load(memory_order_relaxed); + + for (int __round = 0; ; ++__round) + { + if (__current_expected <= 1) + return true; + size_t const __end_node = ((__current_expected + 1) >> 1), + __last_node = __end_node - 1; + for ( ; ; ++__current) + { + if (__current == __end_node) + __current = 0; + auto __expect = __old_phase; + __atomic_phase_ref_t __phase(__state[__current] + .__tickets[__round]); + if (__current == __last_node && (__current_expected & 1)) + { + if (__phase.compare_exchange_strong(__expect, __full_step, + memory_order_acq_rel)) + break; // I'm 1 in 1, go to next __round + } + else if (__phase.compare_exchange_strong(__expect, __half_step, + memory_order_acq_rel)) + { + return false; // I'm 1 in 2, done with arrival + } + else if (__expect == __half_step) + { + if (__phase.compare_exchange_strong(__expect, __full_step, + memory_order_acq_rel)) + break; // I'm 2 in 2, go to next __round + } + } + __current_expected = __last_node + 1; + __current >>= 1; + } + } + }; - for (int __round = 0; ; ++__round) - { - if (__current_expected <= 1) - return true; - size_t const __end_node = ((__current_expected + 1) >> 1), - __last_node = __end_node - 1; - for ( ; ; ++__current) - { - if (__current == __end_node) - __current = 0; - auto __expect = __old_phase; - __atomic_phase_ref_t __phase(_M_state[__current] - .__tickets[__round]); - if (__current == __last_node && (__current_expected & 1)) - { - if (__phase.compare_exchange_strong(__expect, __full_step, - memory_order_acq_rel)) - break; // I'm 1 in 1, go to next __round - } - else if (__phase.compare_exchange_strong(__expect, __half_step, - memory_order_acq_rel)) - { - return false; // I'm 1 in 2, done with arrival - } - else if (__expect == __half_step) - { - if (__phase.compare_exchange_strong(__expect, __full_step, - memory_order_acq_rel)) - break; // I'm 2 in 2, go to next __round - } - } - __current_expected = __last_node + 1; - __current >>= 1; - } - } + template<typename _CompletionF> + class __tree_barrier : public __tree_barrier_base + { + [[no_unique_address]] _CompletionF _M_completion; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3898. Possibly unintended preconditions for completion functions + void _M_invoke_completion() noexcept { _M_completion(); } public: using arrival_token = __barrier_phase_t; - static constexpr ptrdiff_t - max() noexcept - { return __PTRDIFF_MAX__; } - + constexpr __tree_barrier(ptrdiff_t __expected, _CompletionF __completion) - : _M_expected(__expected), _M_expected_adjustment(0), - _M_completion(move(__completion)), - _M_phase(static_cast<__barrier_phase_t>(0)) - { - size_t const __count = (_M_expected + 1) >> 1; - - _M_state = std::make_unique<__state_t[]>(__count); - } + : __tree_barrier_base(__expected), _M_completion(std::move(__completion)) + { } [[nodiscard]] arrival_token arrive(ptrdiff_t __update) { + __glibcxx_assert(__update > 0); + // FIXME: Check that update is less than or equal to the expected count + // for the current barrier phase. + std::hash<std::thread::id> __hasher; size_t __current = __hasher(std::this_thread::get_id()); __atomic_phase_ref_t __phase(_M_phase); const auto __old_phase = __phase.load(memory_order_relaxed); const auto __cur = static_cast<unsigned char>(__old_phase); - for(; __update; --__update) + + if (__cur == 0 && !_M_state.load(memory_order_relaxed)) [[unlikely]] + { + auto __p = _M_alloc_state(); + __state_t* __val = nullptr; + if (_M_state.compare_exchange_strong(__val, __p.get(), + memory_order_seq_cst, + memory_order_acquire)) + __p.release(); + } + + for (; __update; --__update) { - if(_M_arrive(__old_phase, __current)) + if (_M_arrive(__old_phase, __current)) { - _M_completion(); + _M_invoke_completion(); _M_expected += _M_expected_adjustment.load(memory_order_relaxed); _M_expected_adjustment.store(0, memory_order_relaxed); auto __new_phase = static_cast<__barrier_phase_t>(__cur + 2); @@ -194,11 +231,7 @@ It looks different from literature pseudocode for two main reasons: wait(arrival_token&& __old_phase) const { __atomic_phase_const_ref_t __phase(_M_phase); - auto const __test_fn = [=] - { - return __phase.load(memory_order_acquire) != __old_phase; - }; - std::__atomic_wait_address(&_M_phase, __test_fn); + __phase.wait(__old_phase, memory_order_acquire); } void @@ -212,6 +245,8 @@ It looks different from literature pseudocode for two main reasons: template<typename _CompletionF = __empty_completion> class barrier { + static_assert(is_invocable_v<_CompletionF&>); + // Note, we may introduce a "central" barrier algorithm at some point // for more space constrained targets using __algorithm_t = __tree_barrier<_CompletionF>; @@ -236,7 +271,7 @@ It looks different from literature pseudocode for two main reasons: max() noexcept { return __algorithm_t::max(); } - explicit + constexpr explicit barrier(ptrdiff_t __count, _CompletionF __completion = _CompletionF()) : _M_b(__count, std::move(__completion)) { } diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit index a481781..fd75edf 100644 --- a/libstdc++-v3/include/std/bit +++ b/libstdc++-v3/include/std/bit @@ -153,18 +153,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // __cpp_lib_byteswap /// @cond undocumented +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr template<typename _Tp> constexpr _Tp __rotl(_Tp __x, int __s) noexcept { constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits; - if _GLIBCXX17_CONSTEXPR ((_Nd & (_Nd - 1)) == 0) + if constexpr ((_Nd & (_Nd - 1)) == 0) { // Variant for power of two _Nd which the compiler can // easily pattern match. constexpr unsigned __uNd = _Nd; - const unsigned __r = __s; + const auto __r = static_cast<unsigned>(__s); return (__x << (__r % __uNd)) | (__x >> ((-__r) % __uNd)); } const int __r = __s % _Nd; @@ -181,12 +183,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __rotr(_Tp __x, int __s) noexcept { constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits; - if _GLIBCXX17_CONSTEXPR ((_Nd & (_Nd - 1)) == 0) + if constexpr ((_Nd & (_Nd - 1)) == 0) { // Variant for power of two _Nd which the compiler can // easily pattern match. constexpr unsigned __uNd = _Nd; - const unsigned __r = __s; + const auto __r = static_cast<unsigned>(__s); return (__x >> (__r % __uNd)) | (__x << ((-__r) % __uNd)); } const int __r = __s % _Nd; @@ -215,17 +217,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto _Nd_ul = __int_traits<unsigned long>::__digits; constexpr auto _Nd_u = __int_traits<unsigned>::__digits; - if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u) + if constexpr (_Nd <= _Nd_u) { constexpr int __diff = _Nd_u - _Nd; return __builtin_clz(__x) - __diff; } - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ul) + else if constexpr (_Nd <= _Nd_ul) { constexpr int __diff = _Nd_ul - _Nd; return __builtin_clzl(__x) - __diff; } - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ull) + else if constexpr (_Nd <= _Nd_ull) { constexpr int __diff = _Nd_ull - _Nd; return __builtin_clzll(__x) - __diff; @@ -272,11 +274,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto _Nd_ul = __int_traits<unsigned long>::__digits; constexpr auto _Nd_u = __int_traits<unsigned>::__digits; - if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u) + if constexpr (_Nd <= _Nd_u) return __builtin_ctz(__x); - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ul) + else if constexpr (_Nd <= _Nd_ul) return __builtin_ctzl(__x); - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ull) + else if constexpr (_Nd <= _Nd_ull) return __builtin_ctzll(__x); else // (_Nd > _Nd_ull) { @@ -314,11 +316,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto _Nd_ul = __int_traits<unsigned long>::__digits; constexpr auto _Nd_u = __int_traits<unsigned>::__digits; - if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u) + if constexpr (_Nd <= _Nd_u) return __builtin_popcount(__x); - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ul) + else if constexpr (_Nd <= _Nd_ul) return __builtin_popcountl(__x); - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ull) + else if constexpr (_Nd <= _Nd_ull) return __builtin_popcountll(__x); else // (_Nd > _Nd_ull) { @@ -357,7 +359,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } using __promoted_type = decltype(__x << 1); - if _GLIBCXX17_CONSTEXPR (!is_same<__promoted_type, _Tp>::value) + if constexpr (!is_same<__promoted_type, _Tp>::value) { // If __x undergoes integral promotion then shifting by _Nd is // not undefined. In order to make the shift undefined, so that @@ -388,6 +390,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return _Nd - std::__countl_zero(__x); } +#pragma GCC diagnostic pop /// @endcond #ifdef __cpp_lib_bitops // C++ >= 20 diff --git a/libstdc++-v3/include/std/bitset b/libstdc++-v3/include/std/bitset index c07117a..92f11f1 100644 --- a/libstdc++-v3/include/std/bitset +++ b/libstdc++-v3/include/std/bitset @@ -61,8 +61,13 @@ #endif #define __glibcxx_want_constexpr_bitset +#define __glibcxx_want_bitset // ...construct from string_view #include <bits/version.h> +#ifdef __cpp_lib_bitset // ...construct from string_view +# include <string_view> +#endif + #define _GLIBCXX_BITSET_BITS_PER_WORD (__CHAR_BIT__ * __SIZEOF_LONG__) #define _GLIBCXX_BITSET_WORDS(__n) \ ((__n) / _GLIBCXX_BITSET_BITS_PER_WORD + \ @@ -715,7 +720,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER namespace __bitset { -#if _GLIBCXX_HOSTED +#ifdef __cpp_lib_bitset // ...construct from string_view + template<typename _CharT> + using __string = std::basic_string_view<_CharT>; +#elif _GLIBCXX_HOSTED template<typename _CharT> using __string = std::basic_string<_CharT>; #else @@ -752,7 +760,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * (Note that %bitset does @e not meet the formal requirements of a * <a href="tables.html#65">container</a>. Mainly, it lacks iterators.) * - * The template argument, @a Nb, may be any non-negative number, + * The template argument, `Nb`, may be any non-negative number, * specifying the number of bits (e.g., "0", "12", "1024*1024"). * * In the general unoptimized case, storage is allocated in word-sized @@ -816,28 +824,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef _Base_bitset<_GLIBCXX_BITSET_WORDS(_Nb)> _Base; typedef unsigned long _WordT; -#if _GLIBCXX_HOSTED - template<class _CharT, class _Traits, class _Alloc> - _GLIBCXX23_CONSTEXPR - void - _M_check_initial_position(const std::basic_string<_CharT, _Traits, _Alloc>& __s, - size_t __position) const + template<class _Str> + _GLIBCXX23_CONSTEXPR void + _M_check_initial_position( + const _Str& __s, typename _Str::size_type __position) const { if (__position > __s.size()) - __throw_out_of_range_fmt(__N("bitset::bitset: __position " - "(which is %zu) > __s.size() " - "(which is %zu)"), - __position, __s.size()); + __throw_out_of_range_fmt( + __N("bitset::bitset:" + " __position (which is %zu) > __s.size() (which is %zu)"), + size_t(__position), size_t(__s.size())); } -#endif // HOSTED _GLIBCXX23_CONSTEXPR void _M_check(size_t __position, const char *__s) const { if (__position >= _Nb) - __throw_out_of_range_fmt(__N("%s: __position (which is %zu) " - ">= _Nb (which is %zu)"), - __s, __position, _Nb); + __throw_out_of_range_fmt( + __N("%s: __position (which is %zu) >= _Nb (which is %zu)"), + __s, size_t(__position), size_t(_Nb)); } _GLIBCXX23_CONSTEXPR @@ -954,12 +959,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if _GLIBCXX_HOSTED /** * Use a subset of a string. - * @param __s A string of @a 0 and @a 1 characters. - * @param __position Index of the first character in @a __s to use; + * @param __s A string of `0` and `1` characters. + * @param __position Index of the first character in `__s` to use; * defaults to zero. - * @throw std::out_of_range If @a pos is bigger the size of @a __s. + * @throw std::out_of_range If `__position > __s.size()`. * @throw std::invalid_argument If a character appears in the string - * which is neither @a 0 nor @a 1. + * which is neither `0` nor `1`. */ template<class _CharT, class _Traits, class _Alloc> _GLIBCXX23_CONSTEXPR @@ -976,13 +981,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /** * Use a subset of a string. - * @param __s A string of @a 0 and @a 1 characters. - * @param __position Index of the first character in @a __s to use. + * @param __s A string of `0` and `1` characters. + * @param __position Index of the first character in `__s` to use. * @param __n The number of characters to copy. - * @throw std::out_of_range If @a __position is bigger the size - * of @a __s. + * @throw std::out_of_range If `__position > __s.size()`. * @throw std::invalid_argument If a character appears in the string - * which is neither @a 0 nor @a 1. + * which is neither `0` nor `1`. */ template<class _CharT, class _Traits, class _Alloc> _GLIBCXX23_CONSTEXPR @@ -1008,17 +1012,50 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } #endif // HOSTED +#ifdef __cpp_lib_bitset + /** + * Use a subset of a string view. + * @param __s A `string_view` of a sequence of `0` and `1` characters. + * @param __position Index of the first character in `__s` to use. + * @param __n The maximum number of characters from `__s` to use. + * @param __zero The character corresponding to the value 0. + * @param __one The character corresponding to the value 1. + * @throw std::out_of_range If `__position > __s.size()`. + * @throw std::invalid_argument If a character appears in `__s` + * which is neither `0` nor `1`. + */ + template<class _CharT, class _Traits> + constexpr explicit + bitset(basic_string_view<_CharT, _Traits> __s, + basic_string_view<_CharT, _Traits>::size_type __position = 0, + basic_string_view<_CharT, _Traits>::size_type __n = + basic_string_view<_CharT, _Traits>::npos, + _CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) + : _Base() + { + _M_check_initial_position(__s, __position); + _M_copy_from_ptr<_CharT, _Traits>( + __s.data(), __s.size(), __position, __n, __zero, __one); + } +#endif + #if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4294. bitset(const CharT*) constructor needs to be constrained /** * Construct from a character %array. - * @param __str An %array of characters @a zero and @a one. + * @param __str An %array of characters `__zero` and `__one`. * @param __n The number of characters to use. * @param __zero The character corresponding to the value 0. * @param __one The character corresponding to the value 1. * @throw std::invalid_argument If a character appears in the string - * which is neither @a __zero nor @a __one. + * which is neither `__zero` nor `__one`. */ - template<typename _CharT> + template<typename _CharT, + typename = _Require<is_trivially_copyable<_CharT>, + is_standard_layout<_CharT>, + is_trivially_default_constructible<_CharT>, + __not_<is_array<_CharT>>>> [[__gnu__::__nonnull__]] _GLIBCXX23_CONSTEXPR explicit @@ -1028,10 +1065,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) : _Base() { -#if _GLIBCXX_HOSTED if (!__str) __throw_logic_error(__N("bitset::bitset(const _CharT*, ...)")); -#endif using _Traits = typename __bitset::__string<_CharT>::traits_type; if (__n == __bitset::__string<_CharT>::npos) @@ -1605,6 +1640,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef std::basic_istream<_CharT, _Traits> __istream_type; typedef typename __istream_type::ios_base __ios_base; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr struct _Buffer { static _GLIBCXX_CONSTEXPR bool _S_use_alloca() { return _Nb <= 256; } @@ -1613,18 +1650,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER ~_Buffer() { - if _GLIBCXX17_CONSTEXPR (!_S_use_alloca()) + if _GLIBCXX_CONSTEXPR (!_S_use_alloca()) delete[] _M_ptr; } _CharT* const _M_ptr; }; _CharT* __ptr; - if _GLIBCXX17_CONSTEXPR (_Buffer::_S_use_alloca()) + if _GLIBCXX_CONSTEXPR (_Buffer::_S_use_alloca()) __ptr = (_CharT*)__builtin_alloca(_Nb); else __ptr = new _CharT[_Nb]; const _Buffer __buf(__ptr); +#pragma GCC diagnostic pop // _GLIBCXX_RESOLVE_LIB_DEFECTS // 303. Bitset input operator underspecified @@ -1673,7 +1711,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { __is._M_setstate(__ios_base::badbit); } } - if _GLIBCXX17_CONSTEXPR (_Nb) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + if _GLIBCXX_CONSTEXPR (_Nb) { if (size_t __len = __ptr - __buf._M_ptr) __x.template _M_copy_from_ptr<_CharT, _Traits>(__buf._M_ptr, __len, @@ -1682,6 +1722,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER else __state |= __ios_base::failbit; } +#pragma GCC diagnostic pop if (__state) __is.setstate(__state); return __is; diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv index 75fcb71..8cf2c0b 100644 --- a/libstdc++-v3/include/std/charconv +++ b/libstdc++-v3/include/std/charconv @@ -35,6 +35,7 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" // __int128 +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr #include <bits/requires_hosted.h> // for error codes @@ -239,7 +240,7 @@ namespace __detail to_chars_result __res; unsigned __len = 0; - if _GLIBCXX17_CONSTEXPR (__gnu_cxx::__int_traits<_Tp>::__digits <= 16) + if constexpr (__gnu_cxx::__int_traits<_Tp>::__digits <= 16) { __len = __val > 077777u ? 6u : __val > 07777u ? 5u @@ -336,7 +337,7 @@ namespace __detail *__first = '0'; return { __first + 1, errc{} }; } - else if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value) + else if constexpr (std::is_signed<_Tp>::value) if (__value < 0) { *__first++ = '-'; @@ -389,6 +390,10 @@ _GLIBCXX_TO_CHARS(unsigned __GLIBCXX_TYPE_INT_N_2) _GLIBCXX_TO_CHARS(signed __GLIBCXX_TYPE_INT_N_3) _GLIBCXX_TO_CHARS(unsigned __GLIBCXX_TYPE_INT_N_3) #endif +#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ +_GLIBCXX_TO_CHARS(signed __int128) +_GLIBCXX_TO_CHARS(unsigned __int128) +#endif #undef _GLIBCXX_TO_CHARS // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -452,7 +457,7 @@ namespace __detail _GLIBCXX20_CONSTEXPR unsigned char __from_chars_alnum_to_val(unsigned char __c) { - if _GLIBCXX17_CONSTEXPR (_DecOnly) + if constexpr (_DecOnly) return static_cast<unsigned char>(__c - '0'); else return __from_chars_alnum_to_val_table<_DecOnly>::value.__data[__c]; @@ -562,7 +567,7 @@ namespace __detail from_chars_result __res{__first, {}}; int __sign = 1; - if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value) + if constexpr (std::is_signed<_Tp>::value) if (__first != __last && *__first == '-') { __sign = -1; @@ -595,7 +600,7 @@ namespace __detail __res.ec = errc::result_out_of_range; else { - if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value) + if constexpr (std::is_signed<_Tp>::value) { _Tp __tmp; if (__builtin_mul_overflow(__val, __sign, &__tmp)) @@ -605,8 +610,8 @@ namespace __detail } else { - if _GLIBCXX17_CONSTEXPR (__gnu_cxx::__int_traits<_Up>::__max - > __gnu_cxx::__int_traits<_Tp>::__max) + if constexpr (__gnu_cxx::__int_traits<_Up>::__max + > __gnu_cxx::__int_traits<_Tp>::__max) { if (__val > __gnu_cxx::__int_traits<_Tp>::__max) __res.ec = errc::result_out_of_range; diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono index 8eb9fd9..f0207ea 100644 --- a/libstdc++-v3/include/std/chrono +++ b/libstdc++-v3/include/std/chrono @@ -22,6 +22,8 @@ // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. +// [time] + /** @file include/chrono * This is a Standard C++ Library header. * @ingroup chrono @@ -42,24 +44,27 @@ # include <bits/c++0x_warning.h> #else +#define __glibcxx_want_chrono +#define __glibcxx_want_chrono_udls +#include <bits/version.h> + #include <bits/chrono.h> -#if __cplusplus >= 202002L +#if __cpp_lib_bitops >= 201907L # include <bit> // __countr_zero #endif -#if __cplusplus >= 202002L && _GLIBCXX_HOSTED +#ifdef __glibcxx_chrono_cxx20 +# include <bits/stl_algo.h> // upper_bound +# include <bits/range_access.h> // begin/end for arrays +#endif +#if __cpp_lib_chrono >= 201803L // C++20 && HOSTED && USE_CXX11_ABI # include <sstream> # include <string> # include <vector> -# include <bits/stl_algo.h> // upper_bound # include <bits/shared_ptr.h> # include <bits/unique_ptr.h> #endif -#define __glibcxx_want_chrono -#define __glibcxx_want_chrono_udls -#include <bits/version.h> - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -79,7 +84,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ namespace chrono { -#if __cplusplus >= 202002L +#ifdef __glibcxx_chrono_cxx20 /// @addtogroup chrono /// @{ struct local_t { }; @@ -175,13 +180,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using period = system_clock::period; using duration = chrono::duration<rep, period>; using time_point = chrono::time_point<tai_clock>; - static constexpr bool is_steady = false; // XXX true for CLOCK_TAI? + static constexpr bool is_steady = false; - // TODO move into lib, use CLOCK_TAI on linux, add extension point. [[nodiscard]] static time_point - now() - { return from_utc(utc_clock::now()); } + now(); // in src/c++20/clock.cc template<typename _Duration> [[nodiscard]] @@ -215,13 +218,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using period = system_clock::period; using duration = chrono::duration<rep, period>; using time_point = chrono::time_point<gps_clock>; - static constexpr bool is_steady = false; // XXX + static constexpr bool is_steady = false; - // TODO move into lib, add extension point. [[nodiscard]] static time_point - now() - { return from_utc(utc_clock::now()); } + now(); // in src/c++20/clock.cc template<typename _Duration> [[nodiscard]] @@ -2305,8 +2306,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __r *= 10; return __r; } - - template<typename _Duration> struct __utc_leap_second; } /// @endcond @@ -2481,30 +2480,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __byte_duration<ratio<1>> _M_s{}; bool _M_is_neg{}; __subseconds<precision> _M_ss{}; - - template<typename> friend struct __detail::__utc_leap_second; }; - /// @cond undocumented - namespace __detail - { - // Represents a time that is within a leap second insertion. - template<typename _Duration> - struct __utc_leap_second - { - explicit - __utc_leap_second(const sys_time<_Duration>& __s) - : _M_date(chrono::floor<days>(__s)), _M_time(__s - _M_date) - { - ++_M_time._M_s; - } - - sys_days _M_date; - hh_mm_ss<common_type_t<_Duration, days>> _M_time; - }; - } - /// @endcond - // 12/24 HOURS FUNCTIONS constexpr bool @@ -3345,7 +3322,7 @@ namespace __detail #endif // C++20 } // namespace chrono -#if __cplusplus >= 202002L +#ifdef __glibcxx_chrono_cxx20 inline namespace literals { inline namespace chrono_literals @@ -3374,7 +3351,7 @@ namespace __detail _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#if __cplusplus >= 202002L && _GLIBCXX_HOSTED +#if defined __glibcxx_chrono_cxx20 && _GLIBCXX_HOSTED # include <bits/chrono_io.h> #endif diff --git a/libstdc++-v3/include/std/complex b/libstdc++-v3/include/std/complex index 59ef905..4765425 100644 --- a/libstdc++-v3/include/std/complex +++ b/libstdc++-v3/include/std/complex @@ -96,7 +96,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> _GLIBCXX20_CONSTEXPR complex<_Tp> conj(const complex<_Tp>&); /// Return complex with magnitude @a rho and angle @a theta. - template<typename _Tp> complex<_Tp> polar(const _Tp&, const _Tp& = 0); + template<typename _Tp> complex<_Tp> polar(const _Tp&, const _Tp& = _Tp(0)); // Transcendentals: /// Return complex cosine of @a z. @@ -969,7 +969,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif - // 26.2.7/4: arg(__z): Returns the phase angle of __z. + // C++11 26.4.7 [complex.value.ops]/4: arg(z): Returns the phase angle of z. template<typename _Tp> inline _Tp __complex_arg(const complex<_Tp>& __z) @@ -1038,7 +1038,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline complex<_Tp> polar(const _Tp& __rho, const _Tp& __theta) { - __glibcxx_assert( __rho >= 0 ); + __glibcxx_assert( __rho >= _Tp(0) ); return complex<_Tp>(__rho * cos(__theta), __rho * sin(__theta)); } @@ -1238,13 +1238,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__x == _Tp()) { - _Tp __t = sqrt(abs(__y) / 2); + _Tp __t = sqrt(abs(__y) / _Tp(2)); return complex<_Tp>(__t, __y < _Tp() ? -__t : __t); } else { - _Tp __t = sqrt(2 * (std::abs(__z) + abs(__x))); - _Tp __u = __t / 2; + _Tp __t = sqrt(_Tp(2) * (std::abs(__z) + abs(__x))); + _Tp __u = __t / _Tp(2); return __x > _Tp() ? complex<_Tp>(__u, __y / __t) : complex<_Tp>(abs(__y) / __t, __y < _Tp() ? -__u : __u); @@ -1334,7 +1334,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION complex<_Tp> __complex_pow_unsigned(complex<_Tp> __x, unsigned __n) { - complex<_Tp> __y = __n % 2 ? __x : complex<_Tp>(1); + complex<_Tp> __y = __n % 2 ? __x : complex<_Tp>(_Tp(1)); while (__n >>= 1) { @@ -1357,7 +1357,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION pow(const complex<_Tp>& __z, int __n) { return __n < 0 - ? complex<_Tp>(1) / std::__complex_pow_unsigned(__z, -(unsigned)__n) + ? complex<_Tp>(_Tp(1)) / std::__complex_pow_unsigned(__z, + -(unsigned)__n) : std::__complex_pow_unsigned(__z, __n); } @@ -2123,8 +2124,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> std::complex<_Tp> acosh(const std::complex<_Tp>&); template<typename _Tp> std::complex<_Tp> asinh(const std::complex<_Tp>&); template<typename _Tp> std::complex<_Tp> atanh(const std::complex<_Tp>&); - // DR 595. - template<typename _Tp> _Tp fabs(const std::complex<_Tp>&); template<typename _Tp> inline std::complex<_Tp> @@ -2309,7 +2308,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION acos(const std::complex<_Tp>& __z) { return __complex_acos(__z.__rep()); } #else - /// acos(__z) [8.1.2]. + /// acos(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function cacos, defined // in subclause 7.3.5.1. template<typename _Tp> @@ -2345,7 +2344,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION asin(const std::complex<_Tp>& __z) { return __complex_asin(__z.__rep()); } #else - /// asin(__z) [8.1.3]. + /// asin(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function casin, defined // in subclause 7.3.5.2. template<typename _Tp> @@ -2389,7 +2388,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION atan(const std::complex<_Tp>& __z) { return __complex_atan(__z.__rep()); } #else - /// atan(__z) [8.1.4]. + /// atan(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function catan, defined // in subclause 7.3.5.3. template<typename _Tp> @@ -2425,7 +2424,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION acosh(const std::complex<_Tp>& __z) { return __complex_acosh(__z.__rep()); } #else - /// acosh(__z) [8.1.5]. + /// acosh(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function cacosh, defined // in subclause 7.3.6.1. template<typename _Tp> @@ -2464,7 +2463,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION asinh(const std::complex<_Tp>& __z) { return __complex_asinh(__z.__rep()); } #else - /// asinh(__z) [8.1.6]. + /// asinh(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function casin, defined // in subclause 7.3.6.2. template<typename _Tp> @@ -2508,7 +2507,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION atanh(const std::complex<_Tp>& __z) { return __complex_atanh(__z.__rep()); } #else - /// atanh(__z) [8.1.7]. + /// atanh(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function catanh, defined // in subclause 7.3.6.3. template<typename _Tp> @@ -2518,22 +2517,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif template<typename _Tp> + _GLIBCXX11_DEPRECATED_SUGGEST("std::abs") inline _Tp - /// fabs(__z) [8.1.8]. + /// fabs(__z) TR1 8.1.8 [tr.c99.cmplx.fabs] // Effects: Behaves the same as C99 function cabs, defined // in subclause 7.3.8.1. fabs(const std::complex<_Tp>& __z) { return std::abs(__z); } - /// Additional overloads [8.1.9]. + // Additional overloads C++11 26.4.9 [cmplx.over] + template<typename _Tp> inline typename __gnu_cxx::__promote<_Tp>::__type arg(_Tp __x) { typedef typename __gnu_cxx::__promote<_Tp>::__type __type; #if (_GLIBCXX11_USE_C99_MATH && !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) - return std::signbit(__x) ? __type(3.1415926535897932384626433832795029L) - : __type(); + return __builtin_signbit(__type(__x)) + ? __type(3.1415926535897932384626433832795029L) : __type(); #else return std::arg(std::complex<__type>(__x)); #endif diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts index 5899f03..d9920a8 100644 --- a/libstdc++-v3/include/std/concepts +++ b/libstdc++-v3/include/std/concepts @@ -204,7 +204,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { private: template<typename _Tp, typename _Up> - static constexpr bool + static consteval bool _S_noexcept() { if constexpr (__adl_swap<_Tp, _Up>) diff --git a/libstdc++-v3/include/std/debugging b/libstdc++-v3/include/std/debugging new file mode 100644 index 0000000..4cf7e4a --- /dev/null +++ b/libstdc++-v3/include/std/debugging @@ -0,0 +1,77 @@ +// Debugging support -*- C++ -*- + +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file include/debugging + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_DEBUGGING +#define _GLIBCXX_DEBUGGING 1 + +#define __glibcxx_want_debugging +#include <bits/version.h> + +#if __cpp_lib_debugging // C++ >= 26 +namespace std _GLIBCXX_VISIBILITY(default) +{ +// N.B. _GLIBCXX_BEGIN_NAMESPACE_VERSION is not used here. + +/** Try to determine if the program is running under control of a debugger. + * + * On GNU/Linux systems this function will only return true if the program + * is being traced by another program which is known to be a debugger. + * This is determined by checking the command name of the tracing program + * against a list of known debuggers, such as "gdb". + * + * On other POSIX-based systems, this function will return true if the + * program is being traced by any other process, which means it can return + * true for non-debugger utilities that use the ptrace system call. + * + * @since C++26 + */ +bool +is_debugger_present() noexcept; + +/** Stop the program with a breakpoint or debug trap. + * + * The details of how a breakpoint is implemented are platform-specific. + * Some systems provide a special instruction, such as `int3` in x86. + * When no more appropriate mechanism is available, this will stop the + * program using `__builtin_trap()`. It might not be possible for the + * program to continue after such a breakpoint. + * + * @since C++26 + */ +void +breakpoint() noexcept; + +/** Stop the program if it is running under control of a debugger. + * + * @since C++26 + */ +void +breakpoint_if_debugging() noexcept; + +} // namespace std +#endif +#endif // _GLIBCXX_DEBUGGING diff --git a/libstdc++-v3/include/std/expected b/libstdc++-v3/include/std/expected index 5dc1dfb..4eaaab6 100644 --- a/libstdc++-v3/include/std/expected +++ b/libstdc++-v3/include/std/expected @@ -474,6 +474,7 @@ namespace __expected template<typename _Up = remove_cv_t<_Tp>> requires (!is_same_v<remove_cvref_t<_Up>, expected>) && (!is_same_v<remove_cvref_t<_Up>, in_place_t>) + && (!is_same_v<remove_cvref_t<_Up>, unexpect_t>) && is_constructible_v<_Tp, _Up> && (!__expected::__is_unexpected<remove_cvref_t<_Up>>) && __expected::__not_constructing_bool_from_expected<_Tp, _Up> @@ -1169,13 +1170,13 @@ namespace __expected return !__y.has_value() && bool(__x.error() == __y.error()); } - template<typename _Up> + template<typename _Up, same_as<_Tp> _Vp> requires (!__expected::__is_expected<_Up>) && requires (const _Tp& __t, const _Up& __u) { { __t == __u } -> convertible_to<bool>; } friend constexpr bool - operator==(const expected& __x, const _Up& __v) + operator==(const expected<_Vp, _Er>& __x, const _Up& __v) noexcept(noexcept(bool(*__x == __v))) { return __x.has_value() && bool(*__x == __v); } diff --git a/libstdc++-v3/include/std/flat_map b/libstdc++-v3/include/std/flat_map index 405caa8..de006ad 100644 --- a/libstdc++-v3/include/std/flat_map +++ b/libstdc++-v3/include/std/flat_map @@ -873,7 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION [[nodiscard]] friend bool operator==(const _Derived& __x, const _Derived& __y) - { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); } + { + return __x._M_cont.keys == __y._M_cont.keys + && __x._M_cont.values == __y._M_cont.values; + } template<typename _Up = value_type> [[nodiscard]] @@ -890,14 +893,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __x.swap(__y); } template<typename _Predicate> - friend size_type - erase_if(_Derived& __c, _Predicate __pred) + size_type + _M_erase_if(_Predicate __pred) { - auto __guard = __c._M_make_clear_guard(); - auto __zv = views::zip(__c._M_cont.keys, __c._M_cont.values); - auto __sr = ranges::remove_if(__zv, __pred); + auto __guard = _M_make_clear_guard(); + auto __zv = views::zip(_M_cont.keys, _M_cont.values); + auto __sr = ranges::remove_if(__zv, __pred, + [](const auto& __e) { + return const_reference(__e); + }); auto __erased = __sr.size(); - __c.erase(__c.end() - __erased, __c.end()); + erase(end() - __erased, end()); __guard._M_disable(); return __erased; } @@ -1142,14 +1148,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // element access mapped_type& operator[](const key_type& __x) - { return operator[]<const key_type>(__x); } + { return try_emplace(__x).first->second; } mapped_type& operator[](key_type&& __x) - { return operator[]<key_type>(std::move(__x)); } + { return try_emplace(std::move(__x)).first->second; } template<typename _Key2> - requires same_as<remove_cvref_t<_Key2>, _Key> || __transparent_comparator<_Compare> + requires __transparent_comparator<_Compare> mapped_type& operator[](_Key2&& __x) { return try_emplace(std::forward<_Key2>(__x)).first->second; } @@ -1329,6 +1335,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Impl::lower_bound; using _Impl::upper_bound; using _Impl::equal_range; + + using _Impl::_M_erase_if; }; template<typename _KeyContainer, typename _MappedContainer, @@ -1412,6 +1420,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && uses_allocator_v<_MappedContainer, _Alloc>> { }; + template<typename _Key, typename _Tp, typename _Compare, + typename _KeyContainer, typename _MappedContainer, typename _Predicate> + typename flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>::size_type + erase_if(flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& __c, + _Predicate __pred) + { return __c._M_erase_if(std::move(__pred)); } + /* Class template flat_multimap - container adaptor * * @ingroup @@ -1487,6 +1502,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Impl::lower_bound; using _Impl::upper_bound; using _Impl::equal_range; + + using _Impl::_M_erase_if; }; template<typename _KeyContainer, typename _MappedContainer, @@ -1571,6 +1588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && uses_allocator_v<_MappedContainer, _Alloc>> { }; + template<typename _Key, typename _Tp, typename _Compare, + typename _KeyContainer, typename _MappedContainer, typename _Predicate> + typename flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>::size_type + erase_if(flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& __c, + _Predicate __pred) + { return __c._M_erase_if(std::move(__pred)); } + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cpp_lib_flat_map diff --git a/libstdc++-v3/include/std/flat_set b/libstdc++-v3/include/std/flat_set index 3e15d1a..c48340d 100644 --- a/libstdc++-v3/include/std/flat_set +++ b/libstdc++-v3/include/std/flat_set @@ -745,15 +745,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __x.swap(__y); } template<typename _Predicate> - friend size_type - erase_if(_Derived& __c, _Predicate __pred) + size_type + _M_erase_if(_Predicate __pred) { - auto __guard = __c._M_make_clear_guard(); - auto __first = __c._M_cont.begin(); - auto __last = __c._M_cont.end(); + auto __guard = _M_make_clear_guard(); + auto __first = _M_cont.begin(); + auto __last = _M_cont.end(); __first = std::remove_if(__first, __last, __pred); auto __n = __last - __first; - __c.erase(__first, __last); + erase(__first, __last); __guard._M_disable(); return __n; } @@ -860,6 +860,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Impl::lower_bound; using _Impl::upper_bound; using _Impl::equal_range; + + using _Impl::_M_erase_if; }; template<typename _KeyContainer, @@ -930,6 +932,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : bool_constant<uses_allocator_v<_KeyContainer, _Alloc>> { }; + template<typename _Key, typename _Compare, typename _KeyContainer, + typename _Predicate> + typename flat_set<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_set<_Key, _Compare, _KeyContainer>& __c, _Predicate __pred) + { return __c._M_erase_if(std::move(__pred)); } + /* Class template flat_multiset - container adaptor * * @ingroup @@ -999,6 +1007,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Impl::lower_bound; using _Impl::upper_bound; using _Impl::equal_range; + + using _Impl::_M_erase_if; }; template<typename _KeyContainer, @@ -1069,6 +1079,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : bool_constant<uses_allocator_v<_KeyContainer, _Alloc>> { }; + template<typename _Key, typename _Compare, typename _KeyContainer, + typename _Predicate> + typename flat_multiset<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_multiset<_Key, _Compare, _KeyContainer>& __c, _Predicate __pred) + { return __c._M_erase_if(std::move(__pred)); } + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cpp_lib_flat_set diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index e557e10..d6a2170 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -56,7 +56,7 @@ #include <bits/ranges_base.h> // input_range, range_reference_t #include <bits/ranges_util.h> // subrange #include <bits/ranges_algobase.h> // ranges::copy -#include <bits/stl_iterator.h> // back_insert_iterator +#include <bits/stl_iterator.h> // counted_iterator #include <bits/stl_pair.h> // __is_pair #include <bits/unicode.h> // __is_scalar_value, _Utf_view, etc. #include <bits/utility.h> // tuple_size_v @@ -99,24 +99,26 @@ namespace __format // Size for stack located buffer template<typename _CharT> - constexpr size_t __stackbuf_size = 32 * sizeof(void*) / sizeof(_CharT); + constexpr size_t __stackbuf_size = 32 * sizeof(void*) / sizeof(_CharT); // Type-erased character sinks. template<typename _CharT> class _Sink; template<typename _CharT> class _Fixedbuf_sink; - template<typename _Seq> class _Seq_sink; - - template<typename _CharT, typename _Alloc = allocator<_CharT>> - using _Str_sink - = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>; - - // template<typename _CharT, typename _Alloc = allocator<_CharT>> - // using _Vec_sink = _Seq_sink<vector<_CharT, _Alloc>>; + template<typename _Out, typename _CharT> class _Padding_sink; // Output iterator that writes to a type-erase character sink. template<typename _CharT> class _Sink_iter; + // Output iterator that ignores the characters + template<typename _CharT> + class _Drop_iter; + + // An unspecified output iterator type used in the `formattable` concept. + template<typename _CharT> + struct _Iter_for + { using type = _Drop_iter<_CharT>; }; + template<typename _CharT> using __format_context = basic_format_context<_Sink_iter<_CharT>, _CharT>; @@ -135,6 +137,7 @@ namespace __format template<typename, typename...> friend struct std::basic_format_string; }; + } // namespace __format /// @endcond @@ -473,37 +476,33 @@ namespace __format return {0, nullptr}; } - enum _Pres_type { + enum class _Pres_type : unsigned char { _Pres_none = 0, // Default type (not valid for integer presentation types). + _Pres_s = 1, // For strings, bool, ranges // Presentation types for integral types (including bool and charT). - _Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c, - // Presentation types for floating-point types. - _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, _Pres_g, _Pres_G, - _Pres_p = 0, _Pres_P, // For pointers. - _Pres_s = 0, // For strings, bool - _Pres_seq = 0, _Pres_str, // For ranges - _Pres_esc = 0xf, // For strings, charT and ranges + _Pres_c = 2, _Pres_x, _Pres_X, _Pres_d, _Pres_o, _Pres_b, _Pres_B, + // Presentation types for floating-point types + _Pres_g = 1, _Pres_G, _Pres_a, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, + // For pointers, the value are same as hexadecimal presentations for integers + _Pres_p = _Pres_x, _Pres_P = _Pres_X, + _Pres_max = 0xf, }; + using enum _Pres_type; - enum _Align { - _Align_default, - _Align_left, - _Align_right, - _Align_centre, - }; - - enum _Sign { + enum class _Sign : unsigned char { _Sign_default, _Sign_plus, _Sign_minus, // XXX does this need to be distinct from _Sign_default? _Sign_space, }; + using enum _Sign; - enum _WidthPrec { + enum _WidthPrec : unsigned char { _WP_none, // No width/prec specified. _WP_value, // Fixed width/prec specified. _WP_from_arg // Use a formatting argument for width/prec. }; + using enum _WidthPrec; template<typename _Context> size_t @@ -515,9 +514,17 @@ namespace __format constexpr bool __is_xdigit(char __c) { return std::__detail::__from_chars_alnum_to_val(__c) < 16; } + // Used to make _Spec a non-C++98 POD, so the tail-padding is used. + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#pod + struct _SpecBase + { }; + template<typename _CharT> - struct _Spec + struct _Spec : _SpecBase { + unsigned short _M_width; + unsigned short _M_prec; + char32_t _M_fill = ' '; _Align _M_align : 2; _Sign _M_sign : 2; unsigned _M_alt : 1; @@ -525,12 +532,11 @@ namespace __format unsigned _M_zero_fill : 1; _WidthPrec _M_width_kind : 2; _WidthPrec _M_prec_kind : 2; + unsigned _M_debug : 1; _Pres_type _M_type : 4; - unsigned _M_reserved : 1; - unsigned _M_reserved2 : 16; - unsigned short _M_width; - unsigned short _M_prec; - char32_t _M_fill = ' '; + unsigned _M_reserved : 8; + // This class has 8 bits of tail padding, that can be used by + // derived classes. using iterator = typename basic_string_view<_CharT>::iterator; @@ -570,7 +576,7 @@ namespace __format char32_t __c = *__beg++; if (__is_scalar_value(__c)) if (auto __next = __beg.base(); __next != __last) - if (_Align __align = _S_align(*__next)) + if (_Align __align = _S_align(*__next); __align != _Align_default) { _M_fill = __c; _M_align = __align; @@ -579,14 +585,14 @@ namespace __format } } else if (__last - __first >= 2) - if (_Align __align = _S_align(__first[1])) + if (_Align __align = _S_align(__first[1]); __align != _Align_default) { _M_fill = *__first; _M_align = __align; return __first + 2; } - if (_Align __align = _S_align(__first[0])) + if (_Align __align = _S_align(__first[0]); __align != _Align_default) { _M_fill = ' '; _M_align = __align; @@ -611,7 +617,7 @@ namespace __format constexpr iterator _M_parse_sign(iterator __first, iterator) noexcept { - if (_Sign __sign = _S_sign(*__first)) + if (_Sign __sign = _S_sign(*__first); __sign != _Sign_default) { _M_sign = __sign; return __first + 1; @@ -879,18 +885,37 @@ namespace __format const size_t __nfill = __width - __estimated_width; - if (__spec._M_align) + if (__spec._M_align != _Align_default) __align = __spec._M_align; return __format::__write_padded(__fc.out(), __str, __align, __nfill, __spec._M_fill); } - // Values are indices into _Escapes::all. + template<typename _CharT> + size_t + __truncate(basic_string_view<_CharT>& __s, size_t __prec) + { + if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>()) + { + if (__prec != (size_t)-1) + return __unicode::__truncate(__s, __prec); + else + return __unicode::__field_width(__s); + } + else + { + __s = __s.substr(0, __prec); + return __s.size(); + } + } + enum class _Term_char : unsigned char { - _Tc_quote = 12, - _Tc_apos = 15 + _Term_none, + _Term_quote, + _Term_apos, }; + using enum _Term_char; template<typename _CharT> struct _Escapes @@ -901,10 +926,6 @@ namespace __format _Str_view _S_all() { return _GLIBCXX_WIDEN("\t\\t\n\\n\r\\r\\\\\\\"\\\"'\\'\\u\\x"); } - static constexpr - _CharT _S_term(_Term_char __term) - { return _S_all()[static_cast<unsigned char>(__term)]; } - static consteval _Str_view _S_tab() { return _S_all().substr(0, 3); } @@ -936,6 +957,21 @@ namespace __format static consteval _Str_view _S_x() { return _S_all().substr(20, 2); } + + static constexpr + _Str_view _S_term(_Term_char __term) + { + switch (__term) + { + case _Term_none: + return _Str_view(); + case _Term_quote: + return _S_quote().substr(0, 1); + case _Term_apos: + return _S_apos().substr(0, 1); + } + __builtin_unreachable(); + } }; template<typename _CharT> @@ -980,9 +1016,9 @@ namespace __format case _Esc::_S_bslash()[0]: return true; case _Esc::_S_quote()[0]: - return __term == _Term_char::_Tc_quote; + return __term == _Term_quote; case _Esc::_S_apos()[0]: - return __term == _Term_char::_Tc_apos; + return __term == _Term_apos; default: return (__c >= 0 && __c < 0x20) || __c == 0x7f; }; @@ -1051,9 +1087,8 @@ namespace __format case _Esc::_S_apos()[0]: return __format::__write(__out, _Esc::_S_apos().substr(1, 2)); default: - return __format::__write_escape_seq(__out, - static_cast<_UChar>(__c), - _Esc::_S_u()); + return __format::__write_escape_seq( + __out, static_cast<_UChar>(__c), _Esc::_S_u()); } } @@ -1166,8 +1201,7 @@ namespace __format _Out __write_escaped(_Out __out, basic_string_view<_CharT> __str, _Term_char __term) { - *__out = _Escapes<_CharT>::_S_term(__term); - ++__out; + __out = __format::__write(__out, _Escapes<_CharT>::_S_term(__term)); if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>()) __out = __format::__write_escaped_unicode(__out, __str, __term); @@ -1178,8 +1212,7 @@ namespace __format // TODO Handle non-ascii extended encoding __out = __format::__write_escaped_ascii(__out, __str, __term); - *__out = _Escapes<_CharT>::_S_term(__term); - return ++__out; + return __format::__write(__out, _Escapes<_CharT>::_S_term(__term)); } // A lightweight optional<locale>. @@ -1301,11 +1334,14 @@ namespace __format return __first; if (*__first == 's') - ++__first; + { + __spec._M_type = _Pres_s; + ++__first; + } #if __glibcxx_format_ranges // C++ >= 23 && HOSTED else if (*__first == '?') { - __spec._M_type = _Pres_esc; + __spec._M_debug = true; ++__first; } #endif @@ -1321,107 +1357,118 @@ namespace __format format(basic_string_view<_CharT> __s, basic_format_context<_Out, _CharT>& __fc) const { - constexpr auto __term = __format::_Term_char::_Tc_quote; - const auto __write_direct = [&] - { - if (_M_spec._M_type == _Pres_esc) - return __format::__write_escaped(__fc.out(), __s, __term); - else - return __format::__write(__fc.out(), __s); - }; + if (_M_spec._M_debug) + return _M_format_escaped(__s, __fc); if (_M_spec._M_width_kind == _WP_none && _M_spec._M_prec_kind == _WP_none) - return __write_direct(); + return __format::__write(__fc.out(), __s); - const size_t __prec = - _M_spec._M_prec_kind != _WP_none - ? _M_spec._M_get_precision(__fc) - : basic_string_view<_CharT>::npos; + const size_t __maxwidth = _M_spec._M_get_precision(__fc); + const size_t __width = __format::__truncate(__s, __maxwidth); + return __format::__write_padded_as_spec(__s, __width, __fc, _M_spec); + } - const size_t __estimated_width = _S_trunc(__s, __prec); - // N.B. Escaping only increases width - if (_M_spec._M_get_width(__fc) <= __estimated_width - && _M_spec._M_prec_kind == _WP_none) - return __write_direct(); + template<typename _Out> + _Out + _M_format_escaped(basic_string_view<_CharT> __s, + basic_format_context<_Out, _CharT>& __fc) const + { + const size_t __padwidth = _M_spec._M_get_width(__fc); + if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none) + return __format::__write_escaped(__fc.out(), __s, _Term_quote); - if (_M_spec._M_type != _Pres_esc) - return __format::__write_padded_as_spec(__s, __estimated_width, - __fc, _M_spec); + const size_t __maxwidth = _M_spec._M_get_precision(__fc); + const size_t __width = __truncate(__s, __maxwidth); + // N.B. Escaping only increases width + if (__padwidth <= __width && _M_spec._M_prec_kind == _WP_none) + return __format::__write_escaped(__fc.out(), __s, _Term_quote); - __format::_Str_sink<_CharT> __sink; - __format::__write_escaped(__sink.out(), __s, __term); - basic_string_view<_CharT> __escaped(__sink.view().data(), - __sink.view().size()); - const size_t __escaped_width = _S_trunc(__escaped, __prec); // N.B. [tab:format.type.string] defines '?' as // Copies the escaped string ([format.string.escaped]) to the output, // so precision seem to appy to escaped string. - return __format::__write_padded_as_spec(__escaped, __escaped_width, - __fc, _M_spec); + _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth, __maxwidth); + __format::__write_escaped(__sink.out(), __s, _Term_quote); + return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill); } #if __glibcxx_format_ranges // C++ >= 23 && HOSTED template<ranges::input_range _Rg, typename _Out> requires same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, _CharT> - typename basic_format_context<_Out, _CharT>::iterator + _Out _M_format_range(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const { + using _Range = remove_reference_t<_Rg>; using _String = basic_string<_CharT>; using _String_view = basic_string_view<_CharT>; - if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) + if constexpr (!is_lvalue_reference_v<_Rg>) + return _M_format_range<_Range&>(__rg, __fc); + else if constexpr (!is_const_v<_Range> + && __simply_formattable_range<_Range, _CharT>) + return _M_format_range<const _Range&>(__rg, __fc); + else if constexpr (ranges::contiguous_range<_Rg>) + { + _String_view __str(ranges::data(__rg), + size_t(ranges::distance(__rg))); + return format(__str, __fc); + } + else if (!_M_spec._M_debug) + { + const size_t __padwidth = _M_spec._M_get_width(__fc); + if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none) + return ranges::copy(__rg, __fc.out()).out; + + _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth, + _M_spec._M_get_precision(__fc)); + ranges::copy(__rg, __sink.out()); + return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill); + } + else if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) { const size_t __n(ranges::distance(__rg)); - if constexpr (ranges::contiguous_range<_Rg>) - return format(_String_view(ranges::data(__rg), __n), __fc); - else if (__n <= __format::__stackbuf_size<_CharT>) + size_t __w = __n; + if constexpr (!__unicode::__literal_encoding_is_unicode<_CharT>()) + if (size_t __max = _M_spec._M_get_precision(__fc); __n > __max) + __w == __max; + + if (__w <= __format::__stackbuf_size<_CharT>) { _CharT __buf[__format::__stackbuf_size<_CharT>]; - ranges::copy(__rg, __buf); - return format(_String_view(__buf, __n), __fc); + ranges::copy_n(ranges::begin(__rg), __w, __buf); + return _M_format_escaped(_String_view(__buf, __n), __fc); } - else if constexpr (ranges::sized_range<_Rg>) - return format(_String(from_range, __rg), __fc); else if constexpr (ranges::random_access_range<_Rg>) { ranges::iterator_t<_Rg> __first = ranges::begin(__rg); - ranges::subrange __sub(__first, __first + __n); - return format(_String(from_range, __sub), __fc); + ranges::subrange __sub(__first, __first + __w); + return _M_format_escaped(_String(from_range, __sub), __fc); + } + else if (__w <= __n) + { + ranges::subrange __sub( + counted_iterator(ranges::begin(__rg), __w), + default_sentinel); + return _M_format_escaped(_String(from_range, __sub), __fc); } + else if constexpr (ranges::sized_range<_Rg>) + return _M_format_escaped(_String(from_range, __rg), __fc); else { // N.B. preserve the computed size ranges::subrange __sub(__rg, __n); - return format(_String(from_range, __sub), __fc); + return _M_format_escaped(_String(from_range, __sub), __fc); } } else - return format(_String(from_range, __rg), __fc); + return _M_format_escaped(_String(from_range, __rg), __fc); } constexpr void set_debug_format() noexcept - { _M_spec._M_type = _Pres_esc; } + { _M_spec._M_debug = true; } #endif private: - static size_t - _S_trunc(basic_string_view<_CharT>& __s, size_t __prec) - { - if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>()) - { - if (__prec != basic_string_view<_CharT>::npos) - return __unicode::__truncate(__s, __prec); - else - return __unicode::__field_width(__s); - } - else - { - __s = __s.substr(0, __prec); - return __s.size(); - } - } - _Spec<_CharT> _M_spec{}; }; @@ -1434,6 +1481,16 @@ namespace __format static constexpr _Pres_type _AsBool = _Pres_s; static constexpr _Pres_type _AsChar = _Pres_c; + __formatter_int() = default; + + constexpr + __formatter_int(_Spec<_CharT> __spec) noexcept + : _M_spec(__spec) + { + if (_M_spec._M_type == _Pres_none) + _M_spec._M_type = _Pres_d; + } + constexpr typename basic_format_parse_context<_CharT>::iterator _M_do_parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type) { @@ -1521,7 +1578,7 @@ namespace __format case 's': if (__type == _AsBool) { - __spec._M_type = _Pres_s; // same value (and meaning) as "none" + __spec._M_type = _Pres_s; // same meaning as "none" for bool ++__first; } break; @@ -1529,7 +1586,7 @@ namespace __format case '?': if (__type == _AsChar) { - __spec._M_type = _Pres_esc; + __spec._M_debug = true; ++__first; } #endif @@ -1550,7 +1607,8 @@ namespace __format { auto __end = _M_do_parse(__pc, _AsBool); if (_M_spec._M_type == _Pres_s) - if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill) + if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt + || _M_spec._M_zero_fill) __throw_format_error("format error: format-spec contains " "invalid formatting options for " "'bool'"); @@ -1559,8 +1617,9 @@ namespace __format else if constexpr (__char<_Tp>) { auto __end = _M_do_parse(__pc, _AsChar); - if (_M_spec._M_type == _Pres_c || _M_spec._M_type == _Pres_esc) - if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill + if (_M_spec._M_type == _Pres_c) + if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt + || _M_spec._M_zero_fill /* XXX should be invalid? || _M_spec._M_localized */) __throw_format_error("format error: format-spec contains " "invalid formatting options for " @@ -1672,51 +1731,34 @@ namespace __format _M_spec); } - [[__gnu__::__always_inline__]] - static size_t - _S_character_width(_CharT __c) - { - // N.B. single byte cannot encode charcter of width greater than 1 - if constexpr (sizeof(_CharT) > 1u && - __unicode::__literal_encoding_is_unicode<_CharT>()) - return __unicode::__field_width(__c); - else - return 1u; - } - template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator _M_format_character(_CharT __c, - basic_format_context<_Out, _CharT>& __fc) const + basic_format_context<_Out, _CharT>& __fc) const { - return __format::__write_padded_as_spec({&__c, 1u}, - _S_character_width(__c), - __fc, _M_spec); - } + basic_string_view<_CharT> __in(&__c, 1u); + size_t __width = 1u; + // N.B. single byte cannot encode character of width greater than 1 + if constexpr (sizeof(_CharT) > 1u && + __unicode::__literal_encoding_is_unicode<_CharT>()) + __width = __unicode::__field_width(__c); + + if (!_M_spec._M_debug) + return __format::__write_padded_as_spec(__in, __width, + __fc, _M_spec); - template<typename _Out> - typename basic_format_context<_Out, _CharT>::iterator - _M_format_character_escaped(_CharT __c, - basic_format_context<_Out, _CharT>& __fc) const - { - using _Esc = _Escapes<_CharT>; - constexpr auto __term = __format::_Term_char::_Tc_apos; - const basic_string_view<_CharT> __in(&__c, 1u); - if (_M_spec._M_get_width(__fc) <= 3u) - return __format::__write_escaped(__fc.out(), __in, __term); + __width += 2; + if (_M_spec._M_get_width(__fc) <= __width) + return __format::__write_escaped(__fc.out(), __in, _Term_apos); _CharT __buf[12]; - __format::_Fixedbuf_sink<_CharT> __sink(__buf); - __format::__write_escaped(__sink.out(), __in, __term); + _Fixedbuf_sink<_CharT> __sink(__buf); + __format::__write_escaped(__sink.out(), __in, _Term_apos); - const basic_string_view<_CharT> __escaped = __sink.view(); - size_t __estimated_width; - if (__escaped[1] == _Esc::_S_bslash()[0]) // escape sequence - __estimated_width = __escaped.size(); - else - __estimated_width = 2 + _S_character_width(__c); - return __format::__write_padded_as_spec(__escaped, - __estimated_width, + __in = __sink.view(); + if (__in[1] == _Escapes<_CharT>::_S_bslash()[0]) // escape sequence + __width = __in.size(); + return __format::__write_padded_as_spec(__in, __width, __fc, _M_spec); } @@ -1816,37 +1858,27 @@ namespace __format __align, __nfill, __fill_char); } -#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ - template<typename _Tp> - using make_unsigned_t - = typename __conditional_t<(sizeof(_Tp) <= sizeof(long long)), - std::make_unsigned<_Tp>, - type_identity<unsigned __int128>>::type; - - // std::to_chars is not overloaded for int128 in strict mode. - template<typename _Int> - static to_chars_result - to_chars(char* __first, char* __last, _Int __value, int __base) - { return std::__to_chars_i<_Int>(__first, __last, __value, __base); } -#endif - _Spec<_CharT> _M_spec{}; }; +#ifdef __BFLT16_DIG__ + using __bflt16_t = decltype(0.0bf16); +#endif + // Decide how 128-bit floating-point types should be formatted (or not). - // When supported, the typedef __format::__float128_t is the type that - // format arguments should be converted to for storage in basic_format_arg. + // When supported, the typedef __format::__flt128_t is the type that format + // arguments should be converted to before passing them to __formatter_fp. // Define the macro _GLIBCXX_FORMAT_F128 to say they're supported. - // _GLIBCXX_FORMAT_F128=1 means __float128, _Float128 etc. will be formatted - // by converting them to long double (or __ieee128 for powerpc64le). - // _GLIBCXX_FORMAT_F128=2 means basic_format_arg needs to enable explicit - // support for _Float128, rather than formatting it as another type. + // The __float128, _Float128 will be formatted by converting them to: + // __ieee128 (same as __float128) when _GLIBCXX_FORMAT_F128=1, + // long double when _GLIBCXX_FORMAT_F128=2, + // _Float128 when _GLIBCXX_FORMAT_F128=3. #undef _GLIBCXX_FORMAT_F128 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // Format 128-bit floating-point types using __ieee128. - using __float128_t = __ieee128; + using __flt128_t = __ieee128; # define _GLIBCXX_FORMAT_F128 1 #ifdef __LONG_DOUBLE_IEEE128__ @@ -1880,14 +1912,14 @@ namespace __format #elif defined _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128 // Format 128-bit floating-point types using long double. - using __float128_t = long double; -# define _GLIBCXX_FORMAT_F128 1 + using __flt128_t = long double; +# define _GLIBCXX_FORMAT_F128 2 #elif __FLT128_DIG__ && defined(_GLIBCXX_HAVE_FLOAT128_MATH) // Format 128-bit floating-point types using _Float128. - using __float128_t = _Float128; -# define _GLIBCXX_FORMAT_F128 2 + using __flt128_t = _Float128; +# define _GLIBCXX_FORMAT_F128 3 # if __cplusplus == 202002L // These overloads exist in the library, but are not declared for C++20. @@ -2356,9 +2388,16 @@ namespace __format const size_t __r = __str.size() - __e; // Length of remainder. auto __overwrite = [&](_CharT* __p, size_t) { // Apply grouping to the digits before the radix or exponent. - auto __end = std::__add_grouping(__p, __np.thousands_sep(), + int __off = 0; + if (auto __c = __str.front(); __c == '-' || __c == '+' || __c == ' ') + { + *__p = __c; + __off = 1; + } + auto __end = std::__add_grouping(__p + __off, __np.thousands_sep(), __grp.data(), __grp.size(), - __str.data(), __str.data() + __e); + __str.data() + __off, + __str.data() + __e); if (__r) // If there's a fractional part or exponent { if (__d != __str.npos) @@ -2381,6 +2420,150 @@ namespace __format _Spec<_CharT> _M_spec{}; }; + template<__format::__char _CharT> + struct __formatter_ptr + { + __formatter_ptr() = default; + + constexpr + __formatter_ptr(_Spec<_CharT> __spec) noexcept + : _M_spec(__spec) + { _M_set_default(_Pres_p); } + + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type = _Pres_p) + { + __format::_Spec<_CharT> __spec{}; + const auto __last = __pc.end(); + auto __first = __pc.begin(); + + auto __finalize = [this, &__spec, __type] { + _M_spec = __spec; + _M_set_default(__type); + }; + + auto __finished = [&] { + if (__first == __last || *__first == '}') + { + __finalize(); + return true; + } + return false; + }; + + if (__finished()) + return __first; + + __first = __spec._M_parse_fill_and_align(__first, __last); + if (__finished()) + return __first; + +// _GLIBCXX_RESOLVE_LIB_DEFECTS +// P2510R3 Formatting pointers +#if __glibcxx_format >= 202304L + __first = __spec._M_parse_zero_fill(__first, __last); + if (__finished()) + return __first; +#endif + + __first = __spec._M_parse_width(__first, __last, __pc); + if (__finished()) + return __first; + + if (*__first == 'p') + { + __spec._M_type = _Pres_p; + _M_spec._M_alt = !_M_spec._M_alt; + ++__first; + } +#if __glibcxx_format >= 202304L + else if (*__first == 'P') + { + __spec._M_type = _Pres_P; + _M_spec._M_alt = !_M_spec._M_alt; + ++__first; + } +#endif + + if (__finished()) + return __first; + + __format::__failed_to_parse_format_spec(); + } + + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const + { + auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v); + char __buf[2 + sizeof(__v) * 2]; + auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf), + __u, 16); + int __n = __ptr - __buf; + __buf[0] = '0'; + __buf[1] = 'x'; +#if __glibcxx_format >= 202304L + if (_M_spec._M_type == __format::_Pres_P) + { + __buf[1] = 'X'; + for (auto __p = __buf + 2; __p != __ptr; ++__p) +#if __has_builtin(__builtin_toupper) + *__p = __builtin_toupper(*__p); +#else + *__p = std::toupper(*__p); +#endif + } +#endif + + basic_string_view<_CharT> __str; + if constexpr (is_same_v<_CharT, char>) + __str = string_view(__buf, __n); +#ifdef _GLIBCXX_USE_WCHAR_T + else + { + auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT)); + std::__to_wstring_numeric(__buf, __n, __p); + __str = wstring_view(__p, __n); + } +#endif + +#if __glibcxx_format >= 202304L + if (_M_spec._M_zero_fill) + { + size_t __width = _M_spec._M_get_width(__fc); + if (__width <= __str.size()) + return __format::__write(__fc.out(), __str); + + auto __out = __fc.out(); + // Write "0x" or "0X" prefix before zero-filling. + __out = __format::__write(std::move(__out), __str.substr(0, 2)); + __str.remove_prefix(2); + size_t __nfill = __width - __n; + return __format::__write_padded(std::move(__out), __str, + __format::_Align_right, + __nfill, _CharT('0')); + } +#endif + + return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec, + __format::_Align_right); + } + + private: + [[__gnu__::__always_inline__]] + constexpr void + _M_set_default(_Pres_type __type) + { + if (_M_spec._M_type == _Pres_none && __type != _Pres_none) + { + _M_spec._M_type = __type; + _M_spec._M_alt = !_M_spec._M_alt; + } + } + + __format::_Spec<_CharT> _M_spec{}; + }; + } // namespace __format /// @endcond @@ -2400,11 +2583,8 @@ namespace __format typename basic_format_context<_Out, _CharT>::iterator format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const { - if (_M_f._M_spec._M_type == __format::_Pres_none - || _M_f._M_spec._M_type == __format::_Pres_c) + if (_M_f._M_spec._M_type == __format::_Pres_c) return _M_f._M_format_character(__u, __fc); - else if (_M_f._M_spec._M_type == __format::_Pres_esc) - return _M_f._M_format_character_escaped(__u, __fc); else return _M_f.format(static_cast<make_unsigned_t<_CharT>>(__u), __fc); } @@ -2412,7 +2592,7 @@ namespace __format #if __glibcxx_format_ranges // C++ >= 23 && HOSTED constexpr void set_debug_format() noexcept - { _M_f._M_spec._M_type = __format::_Pres_esc; } + { _M_f._M_spec._M_debug = true; } #endif private: @@ -2436,11 +2616,8 @@ namespace __format typename basic_format_context<_Out, wchar_t>::iterator format(char __u, basic_format_context<_Out, wchar_t>& __fc) const { - if (_M_f._M_spec._M_type == __format::_Pres_none - || _M_f._M_spec._M_type == __format::_Pres_c) + if (_M_f._M_spec._M_type == __format::_Pres_c) return _M_f._M_format_character(__u, __fc); - else if (_M_f._M_spec._M_type == __format::_Pres_esc) - return _M_f._M_format_character_escaped(__u, __fc); else return _M_f.format(static_cast<unsigned char>(__u), __fc); } @@ -2448,7 +2625,7 @@ namespace __format #if __glibcxx_format_ranges // C++ >= 23 && HOSTED constexpr void set_debug_format() noexcept - { _M_f._M_spec._M_type = __format::_Pres_esc; } + { _M_f._M_spec._M_debug = true; } #endif private: @@ -2789,8 +2966,8 @@ namespace __format }; #endif -#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 == 1 - // Reuse __formatter_fp<C>::format<__float128_t, Out> for _Float128. +#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 + // Use __formatter_fp<C>::format<__format::__flt128_t, Out> for _Float128. template<__format::__char _CharT> struct formatter<_Float128, _CharT> { @@ -2804,7 +2981,30 @@ namespace __format template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(_Float128 __u, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f.format((__format::__float128_t)__u, __fc); } + { return _M_f.format((__format::__flt128_t)__u, __fc); } + + private: + __format::__formatter_fp<_CharT> _M_f; + }; +#endif + +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 == 2 + // Use __formatter_fp<C>::format<__format::__flt128_t, Out> for __float128, + // when long double is not 128bit IEEE type. + template<__format::__char _CharT> + struct formatter<__float128, _CharT> + { + formatter() = default; + + [[__gnu__::__always_inline__]] + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__float128 __u, basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format((__format::__flt128_t)__u, __fc); } private: __format::__formatter_fp<_CharT> _M_f; @@ -2814,7 +3014,7 @@ namespace __format #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) // Reuse __formatter_fp<C>::format<float, Out> for bfloat16_t. template<__format::__char _CharT> - struct formatter<__gnu_cxx::__bfloat16_t, _CharT> + struct formatter<__format::__bflt16_t, _CharT> { formatter() = default; @@ -2845,120 +3045,15 @@ namespace __format constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { - __format::_Spec<_CharT> __spec{}; - const auto __last = __pc.end(); - auto __first = __pc.begin(); - - auto __finalize = [this, &__spec] { - _M_spec = __spec; - }; - - auto __finished = [&] { - if (__first == __last || *__first == '}') - { - __finalize(); - return true; - } - return false; - }; - - if (__finished()) - return __first; - - __first = __spec._M_parse_fill_and_align(__first, __last); - if (__finished()) - return __first; - -// _GLIBCXX_RESOLVE_LIB_DEFECTS -// P2510R3 Formatting pointers -#if __glibcxx_format >= 202304L - __first = __spec._M_parse_zero_fill(__first, __last); - if (__finished()) - return __first; -#endif - - __first = __spec._M_parse_width(__first, __last, __pc); - - if (__first != __last) - { - if (*__first == 'p') - ++__first; -#if __glibcxx_format >= 202304L - else if (*__first == 'P') - { - __spec._M_type = __format::_Pres_P; - ++__first; - } -#endif - } - - if (__finished()) - return __first; - - __format::__failed_to_parse_format_spec(); - } + { return _M_f.parse(__pc); } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const - { - auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v); - char __buf[2 + sizeof(__v) * 2]; - auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf), - __u, 16); - int __n = __ptr - __buf; - __buf[0] = '0'; - __buf[1] = 'x'; -#if __glibcxx_format >= 202304L - if (_M_spec._M_type == __format::_Pres_P) - { - __buf[1] = 'X'; - for (auto __p = __buf + 2; __p != __ptr; ++__p) -#if __has_builtin(__builtin_toupper) - *__p = __builtin_toupper(*__p); -#else - *__p = std::toupper(*__p); -#endif - } -#endif - - basic_string_view<_CharT> __str; - if constexpr (is_same_v<_CharT, char>) - __str = string_view(__buf, __n); -#ifdef _GLIBCXX_USE_WCHAR_T - else - { - auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT)); - std::__to_wstring_numeric(__buf, __n, __p); - __str = wstring_view(__p, __n); - } -#endif - -#if __glibcxx_format >= 202304L - if (_M_spec._M_zero_fill) - { - size_t __width = _M_spec._M_get_width(__fc); - if (__width <= __str.size()) - return __format::__write(__fc.out(), __str); - - auto __out = __fc.out(); - // Write "0x" or "0X" prefix before zero-filling. - __out = __format::__write(std::move(__out), __str.substr(0, 2)); - __str.remove_prefix(2); - size_t __nfill = __width - __n; - return __format::__write_padded(std::move(__out), __str, - __format::_Align_right, - __nfill, _CharT('0')); - } -#endif - - return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec, - __format::_Align_right); - } + { return _M_f.format(__v, __fc); } private: - __format::_Spec<_CharT> _M_spec{}; + __format::__formatter_ptr<_CharT> _M_f; }; template<__format::__char _CharT> @@ -2977,7 +3072,7 @@ namespace __format { return _M_f.format(__v, __fc); } private: - formatter<const void*, _CharT> _M_f; + __format::__formatter_ptr<_CharT> _M_f; }; template<__format::__char _CharT> @@ -2996,7 +3091,7 @@ namespace __format { return _M_f.format(nullptr, __fc); } private: - formatter<const void*, _CharT> _M_f; + __format::__formatter_ptr<_CharT> _M_f; }; /// @} @@ -3004,79 +3099,30 @@ namespace __format // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3944. Formatters converting sequences of char to sequences of wchar_t - namespace __format { struct __disabled; } + struct __formatter_disabled + { + __formatter_disabled() = delete; // Cannot format char sequence to wchar_t + __formatter_disabled(const __formatter_disabled&) = delete; + __formatter_disabled& operator=(const __formatter_disabled&) = delete; + }; - // std::formatter<__disabled, C> uses the primary template, which is disabled. template<> struct formatter<char*, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<> struct formatter<const char*, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<size_t _Nm> struct formatter<char[_Nm], wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<class _Traits, class _Allocator> struct formatter<basic_string<char, _Traits, _Allocator>, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<class _Traits> struct formatter<basic_string_view<char, _Traits>, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; #endif -/// @cond undocumented -namespace __format -{ - template<typename _Tp, typename _Context, - typename _Formatter - = typename _Context::template formatter_type<remove_const_t<_Tp>>, - typename _ParseContext - = basic_format_parse_context<typename _Context::char_type>> - concept __parsable_with - = semiregular<_Formatter> - && requires (_Formatter __f, _ParseContext __pc) - { - { __f.parse(__pc) } -> same_as<typename _ParseContext::iterator>; - }; - - template<typename _Tp, typename _Context, - typename _Formatter - = typename _Context::template formatter_type<remove_const_t<_Tp>>, - typename _ParseContext - = basic_format_parse_context<typename _Context::char_type>> - concept __formattable_with - = semiregular<_Formatter> - && requires (const _Formatter __cf, _Tp&& __t, _Context __fc) - { - { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>; - }; - - // An unspecified output iterator type used in the `formattable` concept. - template<typename _CharT> - using _Iter_for = back_insert_iterator<basic_string<_CharT>>; - - template<typename _Tp, typename _CharT, - typename _Context = basic_format_context<_Iter_for<_CharT>, _CharT>> - concept __formattable_impl - = __parsable_with<_Tp, _Context> && __formattable_with<_Tp, _Context>; - - template<typename _Formatter> - concept __has_debug_format = requires(_Formatter __f) - { - __f.set_debug_format(); - }; - -} // namespace __format -/// @endcond - -#if __glibcxx_format_ranges // C++ >= 23 && HOSTED - // [format.formattable], concept formattable - template<typename _Tp, typename _CharT> - concept formattable - = __format::__formattable_impl<remove_reference_t<_Tp>, _CharT>; - -#endif // format_ranges - /// An iterator after the last character written, and the number of /// characters that would have been written. template<typename _Out> @@ -3094,6 +3140,43 @@ _GLIBCXX_END_NAMESPACE_CONTAINER namespace __format { template<typename _CharT> + class _Drop_iter + { + public: + using iterator_category = output_iterator_tag; + using value_type = void; + using difference_type = ptrdiff_t; + using pointer = void; + using reference = void; + + _Drop_iter() = default; + _Drop_iter(const _Drop_iter&) = default; + _Drop_iter& operator=(const _Drop_iter&) = default; + + [[__gnu__::__always_inline__]] + constexpr _Drop_iter& + operator=(_CharT __c) + { return *this; } + + [[__gnu__::__always_inline__]] + constexpr _Drop_iter& + operator=(basic_string_view<_CharT> __s) + { return *this; } + + [[__gnu__::__always_inline__]] + constexpr _Drop_iter& + operator*() { return *this; } + + [[__gnu__::__always_inline__]] + constexpr _Drop_iter& + operator++() { return *this; } + + [[__gnu__::__always_inline__]] + constexpr _Drop_iter + operator++(int) { return *this; } + }; + + template<typename _CharT> class _Sink_iter { _Sink<_CharT>* _M_sink = nullptr; @@ -3144,6 +3227,10 @@ namespace __format auto _M_reserve(size_t __n) const { return _M_sink->_M_reserve(__n); } + + bool + _M_discarding() const + { return _M_sink->_M_discarding(); } }; // Abstract base class for type-erased character sinks. @@ -3263,6 +3350,11 @@ namespace __format _M_bump(size_t __n) { _M_next += __n; } + // Returns true if the _Sink is discarding incoming characters. + virtual bool + _M_discarding() const + { return false; } + public: _Sink(const _Sink&) = delete; _Sink& operator=(const _Sink&) = delete; @@ -3318,12 +3410,12 @@ namespace __format // A sink that fills a sequence (e.g. std::string, std::vector, std::deque). // Writes to a buffer then appends that to the sequence when it fills up. template<typename _Seq> - class _Seq_sink final : public _Buf_sink<typename _Seq::value_type> + class _Seq_sink : public _Buf_sink<typename _Seq::value_type> { using _CharT = typename _Seq::value_type; _Seq _M_seq; - + protected: // Transfer buffer contents to the sequence, so buffer can be refilled. void _M_overflow() override @@ -3395,6 +3487,17 @@ namespace __format } } + void _M_trim(span<const _CharT> __s) + requires __is_specialization_of<_Seq, basic_string> + { + _GLIBCXX_DEBUG_ASSERT(__s.data() == this->_M_buf + || __s.data() == _M_seq.data()); + if (__s.data() == _M_seq.data()) + _M_seq.resize(__s.size()); + else + this->_M_reset(this->_M_buf, __s.size()); + } + public: // TODO: for SSO string, use SSO buffer as initial span, then switch // to _M_buf if it overflows? Or even do that for all unused capacity? @@ -3420,7 +3523,7 @@ namespace __format // A writable span that views everything written to the sink. // Will be either a view over _M_seq or the used part of _M_buf. span<_CharT> - view() + _M_span() { auto __s = this->_M_used(); if (_M_seq.size()) @@ -3431,9 +3534,21 @@ namespace __format } return __s; } + + basic_string_view<_CharT> + view() + { + auto __span = _M_span(); + return basic_string_view<_CharT>(__span.data(), __span.size()); + } }; - // A sink that writes to an output iterator. + template<typename _CharT, typename _Alloc = allocator<_CharT>> + using _Str_sink + = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>; + + // template<typename _CharT, typename _Alloc = allocator<_CharT>> + // using _Vec_sink = _Seq_sink<vector<_CharTthis-> sink that writes to an output iterator. // Writes to a fixed-size buffer and then flushes to the output iterator // when the buffer fills up. template<typename _CharT, typename _OutIter> @@ -3465,6 +3580,14 @@ namespace __format _M_count += __s.size(); } + bool + _M_discarding() const override + { + // format_to_n return total number of characters, that would be written, + // see C++20 [format.functions] p20 + return false; + } + public: [[__gnu__::__always_inline__]] explicit @@ -3527,6 +3650,14 @@ namespace __format } } + bool + _M_discarding() const override + { + // format_to_n return total number of characters, that would be written, + // see C++20 [format.functions] p20 + return false; + } + typename _Sink<_CharT>::_Reservation _M_reserve(size_t __n) final { @@ -3601,20 +3732,202 @@ namespace __format } }; - enum _Arg_t : unsigned char { + // A sink for handling the padded outputs (_M_padwidth) or truncated + // (_M_maxwidth). The handling is done by writting to buffer (_Str_strink) + // until sufficient number of characters is written. After that if sequence + // is longer than _M_padwidth it's written to _M_out, and further writes are + // either: + // * buffered and forwarded to _M_out, if below _M_maxwidth, + // * ignored otherwise + // If field width of written sequence is no greater than _M_padwidth, the + // sequence is written during _M_finish call. + template<typename _Out, typename _CharT> + class _Padding_sink : public _Str_sink<_CharT> + { + size_t _M_padwidth; + size_t _M_maxwidth; + _Out _M_out; + size_t _M_printwidth; + + [[__gnu__::__always_inline__]] + bool + _M_ignoring() const + { return _M_printwidth >= _M_maxwidth; } + + [[__gnu__::__always_inline__]] + bool + _M_buffering() const + { + if (_M_printwidth < _M_padwidth) + return true; + if (_M_maxwidth != (size_t)-1) + return _M_printwidth < _M_maxwidth; + return false; + } + + void + _M_sync_discarding() + { + if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>) + if (_M_out._M_discarding()) + _M_maxwidth = _M_printwidth; + } + + void + _M_flush() + { + span<_CharT> __new = this->_M_used(); + basic_string_view<_CharT> __str(__new.data(), __new.size()); + _M_out = __format::__write(std::move(_M_out), __str); + _M_sync_discarding(); + this->_M_rewind(); + } + + bool + _M_force_update() + { + auto __str = this->view(); + // Compute actual field width, possibly truncated. + _M_printwidth = __format::__truncate(__str, _M_maxwidth); + if (_M_ignoring()) + this->_M_trim(__str); + if (_M_buffering()) + return true; + + // We have more characters than padidng, no padding is needed, + // write direclty to _M_out. + if (_M_printwidth >= _M_padwidth) + { + _M_out = __format::__write(std::move(_M_out), __str); + _M_sync_discarding(); + } + // We reached _M_maxwidth that is smaller than _M_padwidth. + // Store the prefix sequence in _M_seq, and free _M_buf. + else + _Str_sink<_CharT>::_M_overflow(); + + // Use internal buffer for writes to _M_out. + this->_M_reset(this->_M_buf); + return false; + } + + bool + _M_update(size_t __new) + { + _M_printwidth += __new; + // Compute estimated width, to see if is not reduced. + if (_M_printwidth >= _M_padwidth || _M_printwidth >= _M_maxwidth) + return _M_force_update(); + return true; + } + + void + _M_overflow() override + { + // Ignore characters in buffer, and override it. + if (_M_ignoring()) + this->_M_rewind(); + // Write buffer to _M_out, and override it. + else if (!_M_buffering()) + _M_flush(); + // Update written count, and if input still should be buffered, + // flush the to _M_seq. + else if (_M_update(this->_M_used().size())) + _Str_sink<_CharT>::_M_overflow(); + } + + bool + _M_discarding() const override + { return _M_ignoring(); } + + typename _Sink<_CharT>::_Reservation + _M_reserve(size_t __n) override + { + // Ignore characters in buffer, if any. + if (_M_ignoring()) + this->_M_rewind(); + else if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>) + if (!_M_buffering()) + { + // Write pending characters if any + if (!this->_M_used().empty()) + _M_flush(); + // Try to reserve from _M_out sink. + if (auto __reserved = _M_out._M_reserve(__n)) + return __reserved; + } + return _Sink<_CharT>::_M_reserve(__n); + } + + void + _M_bump(size_t __n) override + { + // Ignore the written characters. + if (_M_ignoring()) + return; + // If reservation was made directy sink associated _M_out, + // _M_bump will be called on that sink. + _Sink<_CharT>::_M_bump(__n); + if (_M_buffering()) + _M_update(__n); + } + + public: + [[__gnu__::__always_inline__]] + explicit + _Padding_sink(_Out __out, size_t __padwidth, size_t __maxwidth) + : _M_padwidth(__padwidth), _M_maxwidth(__maxwidth), + _M_out(std::move(__out)), _M_printwidth(0) + { _M_sync_discarding(); } + + [[__gnu__::__always_inline__]] + explicit + _Padding_sink(_Out __out, size_t __padwidth) + : _Padding_sink(std::move(__out), __padwidth, (size_t)-1) + { } + + _Out + _M_finish(_Align __align, char32_t __fill_char) + { + // Handle any characters in the buffer. + if (auto __rem = this->_M_used().size()) + { + if (_M_ignoring()) + this->_M_rewind(); + else if (!_M_buffering()) + _M_flush(); + else + _M_update(__rem); + } + + if (!_M_buffering() || !_M_force_update()) + // Characters were already written to _M_out. + if (_M_printwidth >= _M_padwidth) + return std::move(_M_out); + + const auto __str = this->view(); + if (_M_printwidth >= _M_padwidth) + return __format::__write(std::move(_M_out), __str); + + const size_t __nfill = _M_padwidth - _M_printwidth; + return __format::__write_padded(std::move(_M_out), __str, + __align, __nfill, __fill_char); + } + }; + + enum class _Arg_t : unsigned char { _Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull, _Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle, - _Arg_i128, _Arg_u128, - _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, // These are unused. + _Arg_i128, _Arg_u128, _Arg_float128, + _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, + _Arg_max_, + #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT - _Arg_next_value_, - _Arg_f128 = _Arg_ldbl, - _Arg_ibm128 = _Arg_next_value_, -#else - _Arg_f128, + _Arg_ibm128 = _Arg_ldbl, + _Arg_ieee128 = _Arg_float128, #endif - _Arg_max_ }; + using enum _Arg_t; template<typename _Context> struct _Arg_value @@ -3640,6 +3953,12 @@ namespace __format double _M_dbl; #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // No long double if it's ambiguous. long double _M_ldbl; +#else + __ibm128 _M_ibm128; + __ieee128 _M_ieee128; +#endif +#ifdef __SIZEOF_FLOAT128__ + __float128 _M_float128; #endif const _CharT* _M_str; basic_string_view<_CharT> _M_sv; @@ -3649,11 +3968,17 @@ namespace __format __int128 _M_i128; unsigned __int128 _M_u128; #endif -#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT - __ieee128 _M_f128; - __ibm128 _M_ibm128; -#elif _GLIBCXX_FORMAT_F128 == 2 - __float128_t _M_f128; +#ifdef __BFLT16_DIG__ + __bflt16_t _M_bf16; +#endif +#ifdef __FLT16_DIG__ + _Float16 _M_f16; +#endif +#ifdef __FLT32_DIG__ + _Float32 _M_f32; +#endif +#ifdef __FLT64_DIG__ + _Float64 _M_f64; #endif }; @@ -3691,10 +4016,14 @@ namespace __format else if constexpr (is_same_v<_Tp, long double>) return __u._M_ldbl; #else - else if constexpr (is_same_v<_Tp, __ieee128>) - return __u._M_f128; else if constexpr (is_same_v<_Tp, __ibm128>) return __u._M_ibm128; + else if constexpr (is_same_v<_Tp, __ieee128>) + return __u._M_ieee128; +#endif +#ifdef __SIZEOF_FLOAT128__ + else if constexpr (is_same_v<_Tp, __float128>) + return __u._M_float128; #endif else if constexpr (is_same_v<_Tp, const _CharT*>) return __u._M_str; @@ -3708,9 +4037,21 @@ namespace __format else if constexpr (is_same_v<_Tp, unsigned __int128>) return __u._M_u128; #endif -#if _GLIBCXX_FORMAT_F128 == 2 - else if constexpr (is_same_v<_Tp, __float128_t>) - return __u._M_f128; +#ifdef __BFLT16_DIG__ + else if constexpr (is_same_v<_Tp, __bflt16_t>) + return __u._M_bf16; +#endif +#ifdef __FLT16_DIG__ + else if constexpr (is_same_v<_Tp, _Float16>) + return __u._M_f16; +#endif +#ifdef __FLT32_DIG__ + else if constexpr (is_same_v<_Tp, _Float32>) + return __u._M_f32; +#endif +#ifdef __FLT64_DIG__ + else if constexpr (is_same_v<_Tp, _Float64>) + return __u._M_f64; #endif else if constexpr (derived_from<_Tp, _HandleBase>) return static_cast<_Tp&>(__u._M_handle); @@ -3889,36 +4230,25 @@ namespace __format else if constexpr (is_same_v<_Td, __ieee128>) return type_identity<__ieee128>(); #endif - -#if defined(__FLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) - else if constexpr (is_same_v<_Td, _Float16>) - return type_identity<float>(); +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 + else if constexpr (is_same_v<_Td, __float128>) + return type_identity<__float128>(); #endif - -#if defined(__BFLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) - else if constexpr (is_same_v<_Td, decltype(0.0bf16)>) - return type_identity<float>(); +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Td, __format::__bflt16_t>) + return type_identity<__format::__bflt16_t>(); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Td, _Float16>) + return type_identity<_Float16>(); #endif - #if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) else if constexpr (is_same_v<_Td, _Float32>) - return type_identity<float>(); + return type_identity<_Float32>(); #endif - #if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) else if constexpr (is_same_v<_Td, _Float64>) - return type_identity<double>(); -#endif - -#if _GLIBCXX_FORMAT_F128 -# if __FLT128_DIG__ - else if constexpr (is_same_v<_Td, _Float128>) - return type_identity<__format::__float128_t>(); -# endif -# if __SIZEOF_FLOAT128__ - else if constexpr (is_same_v<_Td, __float128>) - return type_identity<__format::__float128_t>(); -# endif + return type_identity<_Float64>(); #endif else if constexpr (__is_specialization_of<_Td, basic_string_view> || __is_specialization_of<_Td, basic_string>) @@ -3974,7 +4304,27 @@ namespace __format else if constexpr (is_same_v<_Tp, __ibm128>) return _Arg_ibm128; else if constexpr (is_same_v<_Tp, __ieee128>) - return _Arg_f128; + return _Arg_ieee128; +#endif +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 + else if constexpr (is_same_v<_Tp, __float128>) + return _Arg_float128; +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Tp, __format::__bflt16_t>) + return _Arg_bf16; +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Tp, _Float16>) + return _Arg_f16; +#endif +#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Tp, _Float32>) + return _Arg_f32; +#endif +#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + else if constexpr (is_same_v<_Tp, _Float64>) + return _Arg_f64; #endif else if constexpr (is_same_v<_Tp, const _CharT*>) return _Arg_str; @@ -3988,11 +4338,6 @@ namespace __format else if constexpr (is_same_v<_Tp, unsigned __int128>) return _Arg_u128; #endif - -#if _GLIBCXX_FORMAT_F128 == 2 - else if constexpr (is_same_v<_Tp, __format::__float128_t>) - return _Arg_f128; -#endif else if constexpr (is_same_v<_Tp, handle>) return _Arg_handle; } @@ -4065,13 +4410,33 @@ namespace __format #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT case _Arg_ldbl: return std::forward<_Visitor>(__vis)(_M_val._M_ldbl); +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 + case _Arg_float128: + return std::forward<_Visitor>(__vis)(_M_val._M_float128); +#endif #else - case _Arg_f128: - return std::forward<_Visitor>(__vis)(_M_val._M_f128); case _Arg_ibm128: return std::forward<_Visitor>(__vis)(_M_val._M_ibm128); + case _Arg_ieee128: + return std::forward<_Visitor>(__vis)(_M_val._M_ieee128); #endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + case _Arg_bf16: + return std::forward<_Visitor>(__vis)(_M_val._M_bf16); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + case _Arg_f16: + return std::forward<_Visitor>(__vis)(_M_val._M_f16); +#endif +#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + case _Arg_f32: + return std::forward<_Visitor>(__vis)(_M_val._M_f32); +#endif +#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + case _Arg_f64: + return std::forward<_Visitor>(__vis)(_M_val._M_f64); #endif +#endif // __glibcxx_to_chars case _Arg_str: return std::forward<_Visitor>(__vis)(_M_val._M_str); case _Arg_sv: @@ -4089,14 +4454,7 @@ namespace __format case _Arg_u128: return std::forward<_Visitor>(__vis)(_M_val._M_u128); #endif - -#if _GLIBCXX_FORMAT_F128 == 2 - case _Arg_f128: - return std::forward<_Visitor>(__vis)(_M_val._M_f128); -#endif - default: - // _Arg_f16 etc. __builtin_unreachable(); } } @@ -4182,7 +4540,7 @@ namespace __format { __UINT64_TYPE__ __packed_types = 0; for (auto __i = __types.rbegin(); __i != __types.rend(); ++__i) - __packed_types = (__packed_types << _Bits) | *__i; + __packed_types = (__packed_types << _Bits) | (unsigned)*__i; return __packed_types; } } // namespace __format @@ -4195,7 +4553,7 @@ namespace __format static constexpr int _S_packed_type_mask = 0b11111; static constexpr int _S_max_packed_args = 12; - static_assert( __format::_Arg_max_ <= (1 << _S_packed_type_bits) ); + static_assert( (unsigned)__format::_Arg_max_ <= (1u << _S_packed_type_bits) ); template<typename... _Args> using _Store = __format::_Arg_store<_Context, _Args...>; @@ -5147,24 +5505,7 @@ namespace __format #endif #if __glibcxx_format_ranges // C++ >= 23 && HOSTED - // [format.range], formatting of ranges - // [format.range.fmtkind], variable template format_kind - enum class range_format { - disabled, - map, - set, - sequence, - string, - debug_string - }; - /// @cond undocumented - template<typename _Rg> - constexpr auto format_kind = - __primary_template_not_defined( - format_kind<_Rg> // you can specialize this for non-const input ranges - ); - template<typename _Tp> consteval range_format __fmt_kind() @@ -5203,74 +5544,49 @@ namespace __format const _Spec<_CharT>& __spec, _Callback&& __call) { - // This is required to implement formatting with padding, - // as we need to format to temporary buffer, using the same iterator. - static_assert(is_same_v<_Out, __format::_Sink_iter<_CharT>>); - - if (__spec._M_get_width(__fc) == 0) - return __call(__fc); - - struct _Restore_out - { - _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>& __fc) - : _M_ctx(std::addressof(__fc)), _M_out(__fc.out()) - { } - - void _M_trigger() - { - if (_M_ctx) - _M_ctx->advance_to(_M_out); - _M_ctx = nullptr; - } - - ~_Restore_out() - { _M_trigger(); } - - private: - basic_format_context<_Sink_iter<_CharT>, _CharT>* _M_ctx; - _Sink_iter<_CharT> _M_out; - }; - - _Restore_out __restore(__fc); - // TODO Consider double sinking, first buffer of width - // size and then original sink, if first buffer is overun - // we do not need to align - _Str_sink<_CharT> __buf; - __fc.advance_to(__buf.out()); - __call(__fc); - __restore._M_trigger(); - - basic_string_view<_CharT> __str(__buf.view()); - size_t __width; - if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>()) - __width = __unicode::__field_width(__str); + if constexpr (is_same_v<_Out, _Drop_iter<_CharT>>) + return __fc.out(); else - __width = __str.size(); + { + // This is required to implement formatting with padding, + // as we need to format to temporary buffer, using the same iterator. + static_assert(is_same_v<_Out, _Sink_iter<_CharT>>); + + const size_t __padwidth = __spec._M_get_width(__fc); + if (__padwidth == 0) + return __call(__fc); + + struct _Restore_out + { + _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>& __fc) + : _M_ctx(std::addressof(__fc)), _M_out(__fc.out()) + { } + + void + _M_disarm() + { _M_ctx = nullptr; } + + ~_Restore_out() + { + if (_M_ctx) + _M_ctx->advance_to(_M_out); + } - return __format::__write_padded_as_spec(__str, __width, __fc, __spec); + private: + basic_format_context<_Sink_iter<_CharT>, _CharT>* _M_ctx; + _Sink_iter<_CharT> _M_out; + }; + + _Restore_out __restore(__fc); + _Padding_sink<_Sink_iter<_CharT>, _CharT> __sink(__fc.out(), __padwidth); + __fc.advance_to(__sink.out()); + __call(__fc); + __fc.advance_to(__sink._M_finish(__spec._M_align, __spec._M_fill)); + __restore._M_disarm(); + return __fc.out(); + } } - template<typename _Rg, typename _CharT> - concept __const_formattable_range - = ranges::input_range<const _Rg> - && formattable<ranges::range_reference_t<const _Rg>, _CharT>; - - // _Rg& and const _Rg& are both formattable and use same formatter - // specialization for their references. - template<typename _Rg, typename _CharT> - concept __simply_formattable_range - = __const_formattable_range<_Rg, _CharT> - && same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, - remove_cvref_t<ranges::range_reference_t<const _Rg>>>; - - template<typename _Rg, typename _CharT> - using __maybe_const_range - = __conditional_t<__const_formattable_range<_Rg, _CharT>, const _Rg, _Rg>; - - template<typename _Tp, typename _CharT> - using __maybe_const - = __conditional_t<formattable<const _Tp, _CharT>, const _Tp, _Tp>; - template<size_t _Pos, typename _Tp, typename _CharT> struct __indexed_formatter_storage { @@ -5493,7 +5809,7 @@ namespace __format }; // [format.range.formatter], class template range_formatter - template<typename _Tp, __format::__char _CharT = char> + template<typename _Tp, __format::__char _CharT> requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT> class range_formatter { @@ -5564,7 +5880,7 @@ namespace __format if (*__first == '?') { ++__first; - __spec._M_type = __format::_Pres_esc; + __spec._M_debug = true; if (__finished() || *__first != 's') __throw_format_error("format error: '?' is allowed only in" " combination with 's'"); @@ -5575,8 +5891,7 @@ namespace __format ++__first; if constexpr (same_as<_Tp, _CharT>) { - if (__spec._M_type != __format::_Pres_esc) - __spec._M_type = __format::_Pres_str; + __spec._M_type = __format::_Pres_s; if (__finished()) return __finalize(); __throw_format_error("format error: element format specifier" @@ -5658,8 +5973,7 @@ namespace __format _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc) const { if constexpr (same_as<_Tp, _CharT>) - if (_M_spec._M_type == __format::_Pres_str - || _M_spec._M_type == __format::_Pres_esc) + if (_M_spec._M_type == __format::_Pres_s) { __format::__formatter_str __fstr(_M_spec); return __fstr._M_format_range(__rg, __fc); @@ -5748,13 +6062,13 @@ namespace __format constexpr void set_separator(basic_string_view<_CharT> __sep) noexcept - requires (!_S_range_format_is_string) + requires (format_kind<_Rg> == range_format::sequence) { _M_under.set_separator(__sep); } constexpr void set_brackets(basic_string_view<_CharT> __open, basic_string_view<_CharT> __close) noexcept - requires (!_S_range_format_is_string) + requires (format_kind<_Rg> == range_format::sequence) { _M_under.set_brackets(__open, __close); } // We deviate from standard, that declares this as template accepting diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 1077e96..f86030d 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -52,6 +52,21 @@ #if __cplusplus >= 201103L +#define __glibcxx_want_boyer_moore_searcher +#define __glibcxx_want_bind_front +#define __glibcxx_want_bind_back +#define __glibcxx_want_constexpr_functional +#define __glibcxx_want_copyable_function +#define __glibcxx_want_function_ref +#define __glibcxx_want_invoke +#define __glibcxx_want_invoke_r +#define __glibcxx_want_move_only_function +#define __glibcxx_want_not_fn +#define __glibcxx_want_ranges +#define __glibcxx_want_reference_wrapper +#define __glibcxx_want_transparent_operators +#include <bits/version.h> + #include <tuple> #include <type_traits> #include <bits/functional_hash.h> @@ -69,26 +84,14 @@ # include <bits/stl_algobase.h> // std::search #endif #if __cplusplus >= 202002L +# include <bits/binders.h> # include <bits/ranges_cmp.h> // std::identity, ranges::equal_to etc. # include <compare> #endif -#if __cplusplus > 202002L && _GLIBCXX_HOSTED -# include <bits/move_only_function.h> +#if __glibcxx_move_only_function || __glibcxx_copyable_function || __glibcxx_function_ref +# include <bits/funcwrap.h> #endif -#define __glibcxx_want_boyer_moore_searcher -#define __glibcxx_want_bind_front -#define __glibcxx_want_bind_back -#define __glibcxx_want_constexpr_functional -#define __glibcxx_want_invoke -#define __glibcxx_want_invoke_r -#define __glibcxx_want_move_only_function -#define __glibcxx_want_not_fn -#define __glibcxx_want_ranges -#define __glibcxx_want_reference_wrapper -#define __glibcxx_want_transparent_operators -#include <bits/version.h> - #endif // C++11 namespace std _GLIBCXX_VISIBILITY(default) @@ -920,115 +923,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #ifdef __cpp_lib_bind_front // C++ >= 20 - - template<typename _Fd, typename... _BoundArgs> - struct _Bind_front - { - static_assert(is_move_constructible_v<_Fd>); - static_assert((is_move_constructible_v<_BoundArgs> && ...)); - - // First parameter is to ensure this constructor is never used - // instead of the copy/move constructor. - template<typename _Fn, typename... _Args> - explicit constexpr - _Bind_front(int, _Fn&& __fn, _Args&&... __args) - noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>, - is_nothrow_constructible<_BoundArgs, _Args>...>::value) - : _M_fd(std::forward<_Fn>(__fn)), - _M_bound_args(std::forward<_Args>(__args)...) - { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); } - -#if __cpp_explicit_this_parameter - template<typename _Self, typename... _CallArgs> - constexpr - invoke_result_t<__like_t<_Self, _Fd>, __like_t<_Self, _BoundArgs>..., _CallArgs...> - operator()(this _Self&& __self, _CallArgs&&... __call_args) - noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>, - __like_t<_Self, _BoundArgs>..., _CallArgs...>) - { - return _S_call(__like_t<_Self, _Bind_front>(__self), _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } -#else - template<typename... _CallArgs> - requires true - constexpr - invoke_result_t<_Fd&, _BoundArgs&..., _CallArgs...> - operator()(_CallArgs&&... __call_args) & - noexcept(is_nothrow_invocable_v<_Fd&, _BoundArgs&..., _CallArgs...>) - { - return _S_call(*this, _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } - - template<typename... _CallArgs> - requires true - constexpr - invoke_result_t<const _Fd&, const _BoundArgs&..., _CallArgs...> - operator()(_CallArgs&&... __call_args) const & - noexcept(is_nothrow_invocable_v<const _Fd&, const _BoundArgs&..., - _CallArgs...>) - { - return _S_call(*this, _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } - - template<typename... _CallArgs> - requires true - constexpr - invoke_result_t<_Fd, _BoundArgs..., _CallArgs...> - operator()(_CallArgs&&... __call_args) && - noexcept(is_nothrow_invocable_v<_Fd, _BoundArgs..., _CallArgs...>) - { - return _S_call(std::move(*this), _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } - - template<typename... _CallArgs> - requires true - constexpr - invoke_result_t<const _Fd, const _BoundArgs..., _CallArgs...> - operator()(_CallArgs&&... __call_args) const && - noexcept(is_nothrow_invocable_v<const _Fd, const _BoundArgs..., - _CallArgs...>) - { - return _S_call(std::move(*this), _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) & = delete; - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) const & = delete; - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) && = delete; - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) const && = delete; -#endif - - private: - using _BoundIndices = index_sequence_for<_BoundArgs...>; - - template<typename _Tp, size_t... _Ind, typename... _CallArgs> - static constexpr - decltype(auto) - _S_call(_Tp&& __g, index_sequence<_Ind...>, _CallArgs&&... __call_args) - { - return std::invoke(std::forward<_Tp>(__g)._M_fd, - std::get<_Ind>(std::forward<_Tp>(__g)._M_bound_args)..., - std::forward<_CallArgs>(__call_args)...); - } - - [[no_unique_address]] _Fd _M_fd; - [[no_unique_address]] std::tuple<_BoundArgs...> _M_bound_args; - }; - - template<typename _Fn, typename... _Args> - using _Bind_front_t = _Bind_front<decay_t<_Fn>, decay_t<_Args>...>; - /** Create call wrapper by partial application of arguments to function. * * The result of `std::bind_front(f, args...)` is a function object that @@ -1050,54 +944,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // __cpp_lib_bind_front #ifdef __cpp_lib_bind_back // C++ >= 23 - template<typename _Fd, typename... _BoundArgs> - struct _Bind_back - { - static_assert(is_move_constructible_v<_Fd>); - static_assert((is_move_constructible_v<_BoundArgs> && ...)); - - // First parameter is to ensure this constructor is never used - // instead of the copy/move constructor. - template<typename _Fn, typename... _Args> - explicit constexpr - _Bind_back(int, _Fn&& __fn, _Args&&... __args) - noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>, - is_nothrow_constructible<_BoundArgs, _Args>...>::value) - : _M_fd(std::forward<_Fn>(__fn)), - _M_bound_args(std::forward<_Args>(__args)...) - { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); } - - template<typename _Self, typename... _CallArgs> - constexpr - invoke_result_t<__like_t<_Self, _Fd>, _CallArgs..., __like_t<_Self, _BoundArgs>...> - operator()(this _Self&& __self, _CallArgs&&... __call_args) - noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>, - _CallArgs..., __like_t<_Self, _BoundArgs>...>) - { - return _S_call(__like_t<_Self, _Bind_back>(__self), _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } - - private: - using _BoundIndices = index_sequence_for<_BoundArgs...>; - - template<typename _Tp, size_t... _Ind, typename... _CallArgs> - static constexpr - decltype(auto) - _S_call(_Tp&& __g, index_sequence<_Ind...>, _CallArgs&&... __call_args) - { - return std::invoke(std::forward<_Tp>(__g)._M_fd, - std::forward<_CallArgs>(__call_args)..., - std::get<_Ind>(std::forward<_Tp>(__g)._M_bound_args)...); - } - - [[no_unique_address]] _Fd _M_fd; - [[no_unique_address]] std::tuple<_BoundArgs...> _M_bound_args; - }; - - template<typename _Fn, typename... _Args> - using _Bind_back_t = _Bind_back<decay_t<_Fn>, decay_t<_Args>...>; - /** Create call wrapper by partial application of arguments to function. * * The result of `std::bind_back(f, args...)` is a function object that @@ -1410,6 +1256,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator()(_RandomAccessIterator2 __first, _RandomAccessIterator2 __last) const { +#ifdef __glibcxx_concepts // >= C++20 + // Value types must be the same for hash function and predicate + // to give consistent results for lookup in the map. + static_assert(is_same_v<iter_value_t<_RAIter>, + iter_value_t<_RandomAccessIterator2>>); +#endif const auto& __pred = this->_M_pred(); auto __patlen = _M_pat_end - _M_pat; if (__patlen == 0) @@ -1471,6 +1323,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator()(_RandomAccessIterator2 __first, _RandomAccessIterator2 __last) const { +#ifdef __glibcxx_concepts // >= C++20 + // Value types must be the same for hash function and predicate + // to give consistent results for lookup in the map. + static_assert(is_same_v<iter_value_t<_RAIter>, + iter_value_t<_RandomAccessIterator2>>); +#endif auto __patlen = _M_pat_end - _M_pat; if (__patlen == 0) return std::make_pair(__first, __first); @@ -1487,7 +1345,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } if (__j < 0) { - const auto __match = __first + __i + 1; + const auto __match = __first + __diff_type(__i + 1); return std::make_pair(__match, __match + __patlen); } __i += std::max(_M_bad_char_shift(__first[__i]), diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index b7ab233..0806900 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -1486,12 +1486,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)> final : __future_base::_Task_state_base<_Res(_Args...)> { +#ifdef __cpp_lib_is_invocable // C++ >= 17 + static_assert(is_invocable_r_v<_Res, _Fn&, _Args...>); +#else + static_assert(__is_invocable<_Fn&, _Args...>::value, + "_Fn& is invocable with _Args..."); +#endif + template<typename _Fn2> _Task_state(_Fn2&& __fn, const _Alloc& __a) : _Task_state_base<_Res(_Args...)>(__a), _M_impl(std::forward<_Fn2>(__fn), __a) { } + template<typename _Fn2> + static shared_ptr<_Task_state_base<_Res(_Args...)>> + _S_create(_Fn2&& __fn, const _Alloc& __a) + { + return std::allocate_shared<_Task_state>(__a, + std::forward<_Fn2>(__fn), + __a); + } + private: virtual void _M_run(_Args&&... __args) @@ -1515,7 +1531,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } virtual shared_ptr<_Task_state_base<_Res(_Args...)>> - _M_reset(); + _M_reset() + { return _S_create(std::move(_M_impl._M_fn), _M_impl); } struct _Impl : _Alloc { @@ -1525,38 +1542,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Fn _M_fn; } _M_impl; }; - - template<typename _Signature, typename _Fn, - typename _Alloc = std::allocator<int>> - shared_ptr<__future_base::_Task_state_base<_Signature>> - __create_task_state(_Fn&& __fn, const _Alloc& __a = _Alloc()) - { - typedef typename decay<_Fn>::type _Fn2; - typedef __future_base::_Task_state<_Fn2, _Alloc, _Signature> _State; - return std::allocate_shared<_State>(__a, std::forward<_Fn>(__fn), __a); - } - - template<typename _Fn, typename _Alloc, typename _Res, typename... _Args> - shared_ptr<__future_base::_Task_state_base<_Res(_Args...)>> - __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)>::_M_reset() - { - return __create_task_state<_Res(_Args...)>(std::move(_M_impl._M_fn), - static_cast<_Alloc&>(_M_impl)); - } /// @endcond /// packaged_task template<typename _Res, typename... _ArgTypes> class packaged_task<_Res(_ArgTypes...)> { - typedef __future_base::_Task_state_base<_Res(_ArgTypes...)> _State_type; + using _State_type = __future_base::_Task_state_base<_Res(_ArgTypes...)>; shared_ptr<_State_type> _M_state; // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3039. Unnecessary decay in thread and packaged_task template<typename _Fn, typename _Fn2 = __remove_cvref_t<_Fn>> - using __not_same - = typename enable_if<!is_same<packaged_task, _Fn2>::value>::type; + using __not_same = __enable_if_t<!is_same<packaged_task, _Fn2>::value>; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4154. The Mandates for std::packaged_task's constructor + // from a callable entity should consider decaying. + template<typename _Fn, typename _Alloc = std::allocator<int>> + using _Task_state + = __future_base::_Task_state<__decay_t<_Fn>, _Alloc, + _Res(_ArgTypes...)>; public: // Construction and destruction @@ -1565,16 +1571,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Fn, typename = __not_same<_Fn>> explicit packaged_task(_Fn&& __fn) - : _M_state( - __create_task_state<_Res(_ArgTypes...)>(std::forward<_Fn>(__fn))) - { -#ifdef __cpp_lib_is_invocable // C++ >= 17 - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 4154. The Mandates for std::packaged_task's constructor - // from a callable entity should consider decaying - static_assert(is_invocable_r_v<_Res, decay_t<_Fn>&, _ArgTypes...>); -#endif - } + : _M_state(_Task_state<_Fn>::_S_create(std::forward<_Fn>(__fn), {})) + { } #if __cplusplus < 201703L // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -1583,8 +1581,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 2921. packaged_task and type-erased allocators template<typename _Fn, typename _Alloc, typename = __not_same<_Fn>> packaged_task(allocator_arg_t, const _Alloc& __a, _Fn&& __fn) - : _M_state(__create_task_state<_Res(_ArgTypes...)>( - std::forward<_Fn>(__fn), __a)) + : _M_state(_Task_state<_Fn, _Alloc>::_S_create(std::forward<_Fn>(__fn), + __a)) { } // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/include/std/inplace_vector b/libstdc++-v3/include/std/inplace_vector new file mode 100644 index 0000000..b5a81be --- /dev/null +++ b/libstdc++-v3/include/std/inplace_vector @@ -0,0 +1,1379 @@ +// Sequence container with fixed capacity -*- C++ -*- + +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file include/inplace_vector + * This is a Standard C++ Library header. + * @ingroup sequences + */ + +#ifndef _GLIBCXX_INPLACE_VECTOR +#define _GLIBCXX_INPLACE_VECTOR 1 + +#pragma GCC system_header + +#define __glibcxx_want_inplace_vector +#include <bits/version.h> + +#ifdef __glibcxx_inplace_vector // C++ >= 26 +#include <compare> +#include <initializer_list> +#include <bits/range_access.h> +#include <bits/ranges_base.h> // borrowed_iterator_t, __detail::__container_compatible_range +#include <bits/ranges_util.h> // subrange +#include <bits/ranges_uninitialized.h> +#include <bits/refwrap.h> +#include <bits/stl_construct.h> +#include <bits/stl_uninitialized.h> +#include <bits/stl_algo.h> // rotate + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // [indirect], class template indirect + template<typename _Tp, size_t _Nm> + class inplace_vector + { + public: + + // types: + using value_type = _Tp; + using pointer = _Tp*; + using const_pointer = const _Tp*; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator + = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>; + using const_iterator + = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + // [containers.sequences.inplace.vector.cons], construct/copy/destroy + constexpr + inplace_vector() noexcept + { _M_init(); } + + constexpr explicit + inplace_vector(size_type __n) + { + _M_init(); + _S_reserve(__n); + std::uninitialized_value_construct_n(data(), __n); + _M_size = __n; + } + + constexpr + inplace_vector(size_type __n, const _Tp& __value) + { + _M_init(); + _S_reserve(__n); + std::uninitialized_fill_n(data(), __n, __value); + _M_size = __n; + } + + template<__any_input_iterator _InputIterator> + constexpr + inplace_vector(_InputIterator __first, _InputIterator __last) + : inplace_vector() + { + if (const auto __n = _S_distance(__first, __last)) + { + _S_reserve(__n); + std::uninitialized_copy(__first, __last, data()); + _M_size = __n; + } + else + { + while (__first != __last) + emplace_back(*__first++); + } + } + + template <__detail::__container_compatible_range<_Tp> _Rg> + constexpr + inplace_vector(from_range_t, _Rg&& __rg) + : inplace_vector() + { append_range(__rg); } + + constexpr + inplace_vector(initializer_list<_Tp> __il) + { + _M_init(); + _S_reserve(__il.size()); + std::uninitialized_copy(__il.begin(), __il.end(), data()); + _M_size = __il.size(); + } + + inplace_vector(const inplace_vector&) + requires is_trivially_copy_constructible_v<_Tp> + = default; + + constexpr + inplace_vector(const inplace_vector& __other) + noexcept(is_nothrow_copy_constructible_v<_Tp>) + { + _M_init(); + std::uninitialized_copy(__other.begin(), __other.end(), data()); + _M_size = __other.size(); + } + + inplace_vector(inplace_vector&&) + requires is_trivially_move_constructible_v<_Tp> + = default; + + constexpr + inplace_vector(inplace_vector&& __other) + noexcept(is_nothrow_move_constructible_v<_Tp>) + { + _M_init(); + std::uninitialized_move(__other.begin(), __other.end(), data()); + _M_size = __other.size(); + } + + ~inplace_vector() + requires is_trivially_destructible_v<_Tp> + = default; + + constexpr + ~inplace_vector() + { clear(); } + + inplace_vector& + operator=(const inplace_vector&) + requires is_trivially_copy_assignable_v<_Tp> + && is_trivially_copy_constructible_v<_Tp> + && is_trivially_destructible_v<_Tp> + = default; + + constexpr inplace_vector& + operator=(const inplace_vector& __other) + noexcept(is_nothrow_copy_assignable_v<_Tp> + && is_nothrow_copy_constructible_v<_Tp>) + { + if (std::addressof(__other) != this) [[likely]] + assign(__other.begin(), __other.end()); + return *this; + } + + inplace_vector& + operator=(inplace_vector&&) + requires is_trivially_move_assignable_v<_Tp> + && is_trivially_move_constructible_v<_Tp> + && is_trivially_destructible_v<_Tp> + = default; + + constexpr inplace_vector& + operator=(inplace_vector&& __other) + noexcept(is_nothrow_move_assignable_v<_Tp> + && is_nothrow_move_constructible_v<_Tp>) + { + if (std::addressof(__other) != this) [[likely]] + assign(std::make_move_iterator(__other.begin()), + std::make_move_iterator(__other.end())); + return *this; + } + + constexpr inplace_vector& + operator=(initializer_list<_Tp> __il) + { + assign(__il.begin(), __il.end()); + return *this; + } + + template<__any_input_iterator _InputIterator> + constexpr void + assign(_InputIterator __first, _InputIterator __last) + { + if (const auto __n = _S_distance(__first, __last)) + { + _S_reserve(__n); + if (_M_size <= __n) + { + for (size_t __i = 0; __i < _M_size; ++__i, (void)++__first) + _M_elems[__i] = *__first; + std::uninitialized_copy(__first, __last, end()); + } + else + std::destroy(std::copy(__first, __last, begin()), end()); + _M_size = __n; + } + else + { + size_t __i = 0; + for (;__first != __last && __i < _M_size; ++__first) + _M_elems[__i++] = *__first; + if (__first == __last) + { + std::_Destroy_n(data() + __i, _M_size - __i); + _M_size = __i; + } + else + { + while (__first != __last) + emplace_back(*__first++); + } + } + } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr void + assign_range(_Rg&& __rg) + { + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) + { + const auto __sz = ranges::distance(__rg); + if (__sz > _Nm) + __throw_bad_alloc(); + if (__sz <= size()) + { + ranges::copy_n(ranges::begin(__rg), __sz, data()); + std::destroy(data() + __sz, data() + _M_size); + } + else + { + auto [__in, __out] = ranges::copy_n( + ranges::begin(__rg), _M_size, + data()); + ranges::uninitialized_copy( + std::move(__in), ranges::end(__rg), + __out, unreachable_sentinel); + } + _M_size = __sz; + } + else + { + auto __in = ranges::begin(__rg); + auto __end = ranges::end(__rg); + size_type __n = 0; + for (; __n < _M_size && __in != __end; ++__in) + _M_elems[__n++] = *__in; + + if (__in == __end) + { + std::destroy(data() + __n, data() + _M_size); + _M_size = __n; + return; + } + else if (__n < _Nm) + { + auto __res = ranges::uninitialized_copy( + std::move(__in), __end, + data() + __n, data() + _Nm); + _M_size = __res.out - data(); + if (__res.in == ranges::end(__rg)) + return; + } + __throw_bad_alloc(); + } + } + + constexpr void + assign(size_type __n, const _Tp& __u) + { + _S_reserve(__n); + if (_M_size <= __n) + std::uninitialized_fill_n(std::fill_n(data(), _M_size, __u), + __n - _M_size, __u); + else + std::destroy_n(std::fill_n(data(), __n, __u), _M_size - __n); + _M_size = __n; + } + + constexpr void + assign(initializer_list<_Tp> __il) + { assign(__il.begin(), __il.end()); } + + // iterators + [[nodiscard]] + constexpr iterator + begin() noexcept { return iterator(data()); } + + [[nodiscard]] + constexpr const_iterator + begin() const noexcept { return const_iterator(data()); } + + [[nodiscard]] + constexpr iterator + end() noexcept + { return iterator(data() + _M_size); } + + [[nodiscard]] + constexpr const_iterator + end() const noexcept + { return const_iterator(data() + _M_size); } + + [[nodiscard]] + constexpr reverse_iterator + rbegin() noexcept + { return reverse_iterator(end()); } + + [[nodiscard]] + constexpr const_reverse_iterator + rbegin() const noexcept + { return const_reverse_iterator(end()); } + + [[nodiscard]] + constexpr reverse_iterator + rend() noexcept { return reverse_iterator(begin()); } + + [[nodiscard]] + constexpr const_reverse_iterator + rend() const noexcept { return const_reverse_iterator(begin()); } + + [[nodiscard]] + constexpr const_iterator + cbegin() const noexcept { return begin(); } + + [[nodiscard]] + constexpr const_iterator + cend() const noexcept { return end(); } + + [[nodiscard]] + constexpr const_reverse_iterator + crbegin() const noexcept { return rbegin(); } + + [[nodiscard]] + constexpr const_reverse_iterator + crend() const noexcept { return rend(); } + + // [containers.sequences.inplace.vector.members] size/capacity + [[nodiscard]] + constexpr bool + empty() const noexcept { return _M_size == 0; } + + [[nodiscard]] + constexpr size_type + size() const noexcept + { + if (_M_size > _Nm) + __builtin_unreachable(); + return _M_size; + } + + [[nodiscard]] + static constexpr size_type + max_size() noexcept { return _Nm; } + + [[nodiscard]] + static constexpr size_type + capacity() noexcept { return _Nm; } + + constexpr void + resize(size_type __n) + { + _S_reserve(__n); + if (__n > _M_size) + std::uninitialized_value_construct_n(data() + _M_size, __n - _M_size); + else if (__n < _M_size) + std::destroy_n(data() + __n, _M_size - __n); + _M_size = __n; + } + + constexpr void + resize(size_type __n, const _Tp& __c) + { + _S_reserve(__n); + if (__n > _M_size) + std::uninitialized_fill_n(data() + _M_size, __n - _M_size, __c); + else if (__n < _M_size) + std::destroy_n(data() + __n, _M_size - __n); + _M_size = __n; + } + + static constexpr void + reserve(size_type __n) + { _S_reserve(__n); } + + static constexpr void + shrink_to_fit() { } + + // element access + [[nodiscard]] + constexpr reference + operator[](size_type __n) + { + __glibcxx_requires_subscript(__n); + return _M_elems[__n]; + } + + [[nodiscard]] + constexpr const_reference + operator[](size_type __n) const + { + __glibcxx_requires_subscript(__n); + return _M_elems[__n]; + } + + [[nodiscard]] + constexpr const_reference + at(size_type __n) const + { + if (__n >= _M_size) + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n " + "(which is %zu) " + ">= size() (which is %zu)"), + __n, _M_size); + return _M_elems[__n]; + } + + [[nodiscard]] + constexpr reference + at(size_type __n) + { + if (__n >= _M_size) + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n " + "(which is %zu) " + ">= size() (which is %zu)"), + __n, _M_size); + return _M_elems[__n]; + } + + [[nodiscard]] + constexpr reference + front() + { + __glibcxx_requires_nonempty(); + return _M_elems[0]; + } + + [[nodiscard]] + constexpr const_reference + front() const + { + __glibcxx_requires_nonempty(); + return _M_elems[0]; + } + + [[nodiscard]] + constexpr reference + back() + { + __glibcxx_requires_nonempty(); + return _M_elems[_M_size - 1]; + } + + [[nodiscard]] + constexpr const_reference + back() const + { + __glibcxx_requires_nonempty(); + return _M_elems[_M_size - 1]; + } + + // [containers.sequences.inplace.vector.data], data access + + [[nodiscard]] + constexpr _Tp* + data() noexcept + { return static_cast<pointer>(_M_elems); } + + [[nodiscard]] + constexpr const _Tp* + data() const noexcept + { return static_cast<const_pointer>(_M_elems); } + + // [containers.sequences.inplace.vector.modifiers], modifiers + template<typename... _Args> + constexpr _Tp& + emplace_back(_Args&&... __args) + { + if (_M_size >= _Nm) + __throw_bad_alloc(); + return unchecked_emplace_back(std::forward<_Args>(__args)...); + } + + constexpr _Tp& + push_back(const _Tp& __x) + { return emplace_back(__x); } + + constexpr _Tp& + push_back(_Tp&& __x) + { return emplace_back(std::move(__x)); } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr void + append_range(_Rg&& __rg) + { + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) + { + const auto __sz = ranges::distance(__rg); + if (__sz > (_Nm - size())) + __throw_bad_alloc(); + // Bounded on output range due PR121143 + ranges::uninitialized_copy( + ranges::begin(__rg), unreachable_sentinel, + data() + _M_size, data() + _M_size + __sz); + _M_size += size_type(__sz); + } + else + { + ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm); + auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail); + _M_size = __out - data(); + if (__in != ranges::end(__rg)) + __throw_bad_alloc(); + } + } + + constexpr void + pop_back() + { + __glibcxx_requires_nonempty(); + --_M_size; + _M_elems[_M_size].~_Tp(); + } + + template<typename... _Args> + constexpr _Tp* + try_emplace_back(_Args&&... __args) + { + if (_M_size >= _Nm) [[unlikely]] + return nullptr; + auto& __r = unchecked_emplace_back(std::forward<_Args>(__args)...); + return __builtin_addressof(__r); + } + + constexpr _Tp* + try_push_back(const _Tp& __x) + { + if (_M_size >= _Nm) [[unlikely]] + return nullptr; + return __builtin_addressof(unchecked_emplace_back(__x)); + } + + constexpr _Tp* + try_push_back(_Tp&& __x) + { + if (_M_size >= _Nm) [[unlikely]] + return nullptr; + return __builtin_addressof(unchecked_emplace_back(std::move(__x))); + } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr ranges::borrowed_iterator_t<_Rg> + try_append_range(_Rg&& __rg) + { + if constexpr (ranges::sized_range<_Rg>) + { + auto __n = ranges::distance(__rg); + if (__n == 0) [[unlikely]] + return ranges::begin(__rg); + + const auto __end = data() + _M_size; + const size_t __avail = _Nm - size(); + if (__n <= __avail) + _M_size += size_type(__n); + else + { + __n = __avail; + _M_size = _Nm; + } + return ranges::uninitialized_copy_n( + ranges::begin(__rg), __n, + __end, unreachable_sentinel).in; + } + else + { + ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm); + auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail); + _M_size = __out - data(); + return std::move(__in); + } + } + + template<typename... _Args> + constexpr _Tp& + unchecked_emplace_back(_Args&&... __args) + { + __glibcxx_assert(_M_size < _Nm); + auto __p = std::construct_at(data() + _M_size, + std::forward<_Args>(__args)...); + ++_M_size; + return *__p; + } + + constexpr _Tp& + unchecked_push_back(const _Tp& __x) + { return unchecked_emplace_back(__x); } + + constexpr _Tp& + unchecked_push_back(_Tp&& __x) + { return unchecked_emplace_back(std::move(__x)); } + + template<typename... _Args> + constexpr iterator + emplace(const_iterator __position, _Args&&... __args) + { + size_t __b = __position - cbegin(); // elements before position + __glibcxx_assert(__b <= _M_size); + if (_M_size >= _Nm) + __throw_bad_alloc(); + iterator __pos = begin() + __b; + std::construct_at(data() + _M_size, std::forward<_Args>(__args)...); + if (_M_size++) + std::rotate(__pos, end() - 1, end()); + return __pos; + } + + constexpr iterator + insert(const_iterator __position, const _Tp& __x) + { return emplace(__position, __x); } + + constexpr iterator + insert(const_iterator __position, _Tp&& __x) + { return emplace(__position, std::move(__x)); } + + constexpr iterator + insert(const_iterator __position, size_type __n, const _Tp& __x) + { + size_t __b = __position - cbegin(); // elements before position + __glibcxx_assert(__b <= _M_size); + if ((_Nm - _M_size) < __n) + __throw_bad_alloc(); + iterator __pos = begin() + __b; + std::uninitialized_fill_n(data() + _M_size, __n, __x); + if (std::__exchange(_M_size, _M_size + __n)) + std::rotate(__pos, end() - __n, end()); + return __pos; + } + + template<__any_input_iterator _InputIterator> + constexpr iterator + insert(const_iterator __position, _InputIterator __first, + _InputIterator __last) + { + size_t __b = __position - cbegin(); // elements before position + __glibcxx_assert(__b <= _M_size); + iterator __pos = begin() + __b; + const size_t __s = _M_size; + if (const auto __n = _S_distance(__first, __last)) + { + if ((_Nm - _M_size) < __n) + __throw_bad_alloc(); + std::uninitialized_copy(__first, __last, data() + _M_size); + _M_size += __n; + } + else + { + while (__first != __last) + emplace_back(*__first++); + } + if (__s) + std::rotate(__pos, begin() + __s, end()); + return __pos; + } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr iterator + insert_range(const_iterator __position, _Rg&& __rg) + { + iterator __pos = begin() + (__position - cbegin()); + const auto __end = end(); + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) + { + const auto __len = ranges::distance(__rg); + if (__len > (_Nm - size())) + __throw_bad_alloc(); + if (!__len) [[unlikely]] + return __pos; + + const size_type __n = size_type(__len); + const size_type __num_after = __end - __pos; + if (__num_after >= __n) + { + ranges::uninitialized_move(__end - __n, __end, + __end, unreachable_sentinel); + _M_size += __n; + ranges::move_backward(__pos, __end - __n, __end); + ranges::copy(__rg, __pos); + } + else if constexpr (ranges::forward_range<_Rg>) + { + auto __mid = ranges::next(ranges::begin(__rg), __num_after); + ranges::uninitialized_copy(__mid, ranges::end(__rg), + __end, unreachable_sentinel); + _M_size += __n - __num_after; + ranges::uninitialized_move(__pos, __end, + __pos + __n, unreachable_sentinel); + _M_size += __num_after; + ranges::copy(ranges::begin(__rg), __mid, __pos); + } + else + { + ranges::uninitialized_copy( + ranges::begin(__rg), ranges::end(__rg), + __end, unreachable_sentinel); + _M_size += __n; + std::rotate(__pos, __end, end()); + } + } + else + { + append_range(__rg); + std::rotate(__pos, __end, end()); + } + return __pos; + } + + constexpr iterator + insert(const_iterator __position, initializer_list<_Tp> __il) + { return insert(__position, __il.begin(), __il.end()); } + + constexpr iterator + erase(const_iterator __position) + { + size_t __n = __position - cbegin(); + __glibcxx_assert(__n < _M_size); + iterator __pos = begin() + __n; + std::move(__pos + 1, end(), __pos); + pop_back(); + return __pos; + } + + constexpr iterator + erase(const_iterator __first, const_iterator __last) + { + size_t __n = __first - cbegin(); + size_t __x = __last - __first; + __glibcxx_assert(__n <= _M_size); + __glibcxx_assert(__x <= _M_size); + iterator __pos = begin() + __n; + iterator __end = std::move(__pos + __x, end(), __pos); + std::destroy_n(__end, __x); + _M_size -= __x; + return __pos; + } + + constexpr void + swap(inplace_vector& __x) + noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>) + { + inplace_vector* __vs[2]{ this, std::addressof(__x) }; + const auto __smaller = __vs[__x.size() < size()]; + const auto __bigger = __vs[__x.size() >= size()]; + size_type __n = __smaller->size(); + size_type __n2 = __bigger->size(); + + if constexpr (is_nothrow_move_constructible_v<_Tp>) + { + for (size_type __i = __n; __i < __n2; ++__i) + { + std::construct_at(__smaller->data() + __i, + std::move(*(__bigger->data() + __i))); + std::destroy_at(__bigger->data() + __i); + } + } + else + { + std::uninitialized_copy(__bigger->data() + __n, + __bigger->data() + __n2, + __smaller->data() + __n); + std::destroy(__bigger->data() + __n, __bigger->data() + __n2); + } + __smaller->_M_size = __n2; + __bigger->_M_size = __n; + + using std::swap; + for (size_type __i = 0; __i < __n; __i++) + swap(_M_elems[__i], __x._M_elems[__i]); + } + + constexpr void + clear() noexcept + { + std::destroy_n(data(), size_t(_M_size)); + _M_size = 0; + } + + constexpr friend bool + operator==(const inplace_vector& __x, const inplace_vector& __y) + { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); } + + constexpr friend auto + operator<=>(const inplace_vector& __x, const inplace_vector& __y) + requires requires (const _Tp __t) { + { __t < __t } -> __detail::__boolean_testable; + } + { + return std::lexicographical_compare_three_way(__x.begin(), __x.end(), + __y.begin(), __y.end(), + __detail::__synth3way); + } + + constexpr friend void + swap(inplace_vector& __x, inplace_vector& __y) + noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>) + { __x.swap(__y); } + + private: + union { + _Tp _M_elems[_Nm]; + }; + + // Check whether integer type _UInt is wide enough to store _Nm, + // so that we use a smaller type for _M_size when that saves space. + template<typename _UInt, bool = (alignof(_Tp) <= sizeof(_UInt))> + static constexpr bool __fits + = _Nm <= __gnu_cxx::__int_traits<_UInt>::__max; + + // Don't bother using a smaller type if alignment of the array elements + // means that it doesn't actually save space. + template<typename _UInt> + static constexpr bool __fits<_UInt, false> = false; + + static consteval auto __select_size_type() + { + if constexpr (__fits<unsigned char>) + return (unsigned char)0; +#if __SHRT_WIDTH__ < __SIZE_WIDTH__ + else if constexpr (__fits<unsigned short>) + return (unsigned short)0; +#endif +#if __INT_WIDTH__ < __SIZE_WIDTH__ && __INT_WIDTH__ > __SHRT_WIDTH__ + else if constexpr (__fits<unsigned int>) + return 0u; +#endif +#if __LONG_WIDTH__ < __SIZE_WIDTH__ && __LONG_WIDTH__ > __INT_WIDTH__ + else if constexpr (__fits<unsigned long>) + return 0ul; +#endif + else // Just use size_t. + return 0uz; + } + decltype(__select_size_type()) _M_size = 0; + + constexpr void + _M_init() + { + if !consteval + { +#if __glibcxx_start_lifetime_as + std::start_lifetime_as_array<_Tp>(data(), _Nm); +#endif + } + else + { + // TODO: use new(_M_elems) _Tp[_Nm]() once PR121068 is fixed + if constexpr (is_trivial_v<_Tp>) + for (size_t __i = 0; __i < _Nm; ++__i) + _M_elems[__i] = _Tp(); + else + __builtin_unreachable(); // only trivial types are supported at compile time + } + } + + static constexpr void + _S_reserve(size_t __n) + { + if (__n > _Nm) + __throw_bad_alloc(); + } + + template<typename _InputIterator> + constexpr static auto + _S_distance(_InputIterator __first, _InputIterator __last) + { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator> + || forward_iterator<_InputIterator>) + return (size_type)ranges::distance(__first, __last); + else if constexpr (derived_from<__iter_category_t<_InputIterator>, + forward_iterator_tag>) + return (size_type)std::distance(__first, __last); + else + return false_type{}; + } + }; + + // [inplace.vector.special], specialized algorithms + template<typename _Tp, size_t _Nm> + constexpr void + swap(inplace_vector<_Tp, _Nm>& __x, inplace_vector<_Tp, _Nm>& __y) + noexcept(noexcept(__x.swap(__y))) + { __x.swap(__y); } + + // specialization for zero capacity, that is required to be trivally copyable + // and empty regardless of _Tp. + template<typename _Tp> + class inplace_vector<_Tp, 0> + { + public: + // types: + using value_type = _Tp; + using pointer = _Tp*; + using const_pointer = const _Tp*; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator + = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>; + using const_iterator + = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + // [containers.sequences.inplace.vector.cons], construct/copy/destroy + inplace_vector() = default; + + constexpr explicit + inplace_vector(size_type __n) + { + if (__n != 0) + __throw_bad_alloc(); + } + + constexpr + inplace_vector(size_type __n, const _Tp& __value) + { + if (__n != 0) + __throw_bad_alloc(); + } + + template<__any_input_iterator _InputIterator> + constexpr + inplace_vector(_InputIterator __first, _InputIterator __last) + { + if (__first != __last) + __throw_bad_alloc(); + } + + template <__detail::__container_compatible_range<_Tp> _Rg> + constexpr + inplace_vector(from_range_t, _Rg&& __rg) + { + if (ranges::begin(__rg) != ranges::end(__rg)) + __throw_bad_alloc(); + } + + constexpr + inplace_vector(initializer_list<_Tp> __il) + { + if (__il.size() != 0) + __throw_bad_alloc(); + } + + inplace_vector(const inplace_vector&) = default; + inplace_vector(inplace_vector&&) = default; + + constexpr + ~inplace_vector() = default; + + inplace_vector& + operator=(const inplace_vector&) = default; + + inplace_vector& + operator=(inplace_vector&&) = default; + + constexpr inplace_vector& + operator=(initializer_list<_Tp> __il) + { + if (__il.size() != 0) + __throw_bad_alloc(); + } + + template<__any_input_iterator _InputIterator> + constexpr void + assign(_InputIterator __first, _InputIterator __last) + { + if (__first != __last) + __throw_bad_alloc(); + } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr void + assign_range(_Rg&& __rg) + { + if (ranges::begin(__rg) != ranges::end(__rg)) + __throw_bad_alloc(); + } + + constexpr void + assign(size_type __n, const _Tp& __u) + { + if (__n != 0) + __throw_bad_alloc(); + } + + constexpr void + assign(initializer_list<_Tp> __il) + { + if (__il.size() != 0) + __throw_bad_alloc(); + } + + // iterators + [[nodiscard]] + constexpr iterator + begin() noexcept { return iterator(nullptr); } + + [[nodiscard]] + constexpr const_iterator + begin() const noexcept { return const_iterator(nullptr); } + + [[nodiscard]] + constexpr iterator + end() noexcept { return iterator(nullptr); } + + [[nodiscard]] + constexpr const_iterator + end() const noexcept { return const_iterator(nullptr); } + + [[nodiscard]] + constexpr reverse_iterator + rbegin() noexcept + { return reverse_iterator(end()); } + + [[nodiscard]] + constexpr const_reverse_iterator + rbegin() const noexcept + { return const_reverse_iterator(end()); } + + [[nodiscard]] + constexpr reverse_iterator + rend() noexcept { return reverse_iterator(begin()); } + + [[nodiscard]] + constexpr const_reverse_iterator + rend() const noexcept { return const_reverse_iterator(begin()); } + + [[nodiscard]] + constexpr const_iterator + cbegin() const noexcept { return begin(); } + + [[nodiscard]] + constexpr const_iterator + cend() const noexcept { return end(); } + + [[nodiscard]] + constexpr const_reverse_iterator + crbegin() const noexcept { return rbegin(); } + + [[nodiscard]] + constexpr const_reverse_iterator + crend() const noexcept { return rend(); } + + // [containers.sequences.inplace.vector.members] size/capacity + [[nodiscard]] + constexpr bool + empty() const noexcept { return true; } + + [[nodiscard]] + constexpr size_type + size() const noexcept { return 0; } + + [[nodiscard]] + static constexpr size_type + max_size() noexcept { return 0; } + + [[nodiscard]] + static constexpr size_type + capacity() noexcept { return 0; } + + constexpr void + resize(size_type __n) + { + if (__n != 0) + __throw_bad_alloc(); + } + + constexpr void + resize(size_type __n, const _Tp&) + { + if (__n != 0) + __throw_bad_alloc(); + } + + static constexpr void + reserve(size_type __n) + { + if (__n != 0) + __throw_bad_alloc(); + } + + static constexpr void + shrink_to_fit() { } + + // element access + [[nodiscard,noreturn]] + constexpr reference + operator[](size_type) + { __builtin_trap(); } + + [[nodiscard,noreturn]] + constexpr const_reference + operator[](size_type) const + { __builtin_trap(); } + + [[nodiscard,noreturn]] + constexpr const_reference + at(size_type __n) const + { + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n " + "(which is %zu) " + ">= size() (which is 0)"), + __n); + } + + [[nodiscard,noreturn]] + constexpr reference + at(size_type __n) + { + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n " + "(which is %zu) " + ">= size() (which is 0)"), + __n); + } + + [[nodiscard,noreturn]] + constexpr reference + front() + { __builtin_trap(); } + + [[nodiscard,noreturn]] + constexpr const_reference + front() const + { __builtin_trap(); } + + [[nodiscard,noreturn]] + constexpr reference + back() + { __builtin_trap(); } + + [[nodiscard,noreturn]] + constexpr const_reference + back() const + { __builtin_trap(); } + + // [containers.sequences.inplace.vector.data], data access + + [[nodiscard]] + constexpr _Tp* + data() noexcept + { return nullptr; } + + [[nodiscard]] + constexpr const _Tp* + data() const noexcept + { return nullptr; } + + // [containers.sequences.inplace.vector.modifiers], modifiers + template<typename... _Args> + [[noreturn]] + constexpr _Tp& + emplace_back(_Args&&...) + { __throw_bad_alloc(); } + + [[noreturn]] + constexpr _Tp& + push_back(const _Tp&) + { __throw_bad_alloc(); } + + [[noreturn]] + constexpr _Tp& + push_back(_Tp&&) + { __throw_bad_alloc(); } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr void + append_range(_Rg&& __rg) + { + if (ranges::begin(__rg) != ranges::end(__rg)) + __throw_bad_alloc(); + } + + [[noreturn]] + constexpr void + pop_back() + { __builtin_trap(); } + + template<typename... _Args> + constexpr _Tp* + try_emplace_back(_Args&&...) + { return nullptr; } + + constexpr _Tp* + try_push_back(const _Tp&) + { return nullptr; } + + constexpr _Tp* + try_push_back(_Tp&&) + { return nullptr; } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr ranges::borrowed_iterator_t<_Rg> + try_append_range(_Rg&& __rg) + { return ranges::begin(__rg); } + + template<typename... _Args> + [[noreturn]] + constexpr _Tp& + unchecked_emplace_back(_Args&&...) + { __builtin_trap(); } + + [[noreturn]] + constexpr _Tp& + unchecked_push_back(const _Tp&) + { __builtin_trap(); } + + [[noreturn]] + constexpr _Tp& + unchecked_push_back(_Tp&&) + { __builtin_trap(); } + + template<typename... _Args> + [[noreturn]] + constexpr iterator + emplace(const_iterator, _Args&&...) + { __throw_bad_alloc(); } + + [[noreturn]] + constexpr iterator + insert(const_iterator, const _Tp&) + { __throw_bad_alloc(); } + + [[noreturn]] + constexpr iterator + insert(const_iterator, _Tp&&) + { __throw_bad_alloc(); } + + constexpr iterator + insert(const_iterator, size_type __n, const _Tp&) + { + if (__n != 0) + __throw_bad_alloc(); + return begin(); + } + + template<typename _InputIterator> + constexpr iterator + insert(const_iterator, _InputIterator __first, _InputIterator __last) + { + if (__first != __last) + __throw_bad_alloc(); + return begin(); + } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr iterator + insert_range(const_iterator, _Rg&& __rg) + { + if (ranges::begin(__rg) != ranges::end(__rg)) + __throw_bad_alloc(); + return begin(); + } + + constexpr iterator + insert(const_iterator, initializer_list<_Tp> __il) + { + if (__il.size() != 0) + __throw_bad_alloc(); + return begin(); + } + + [[noreturn]] + constexpr iterator + erase(const_iterator) + { __builtin_trap(); } + + constexpr iterator + erase(const_iterator __first, const_iterator __last) + { + __glibcxx_assert(__first == __last); + return begin(); + } + + constexpr void + swap(inplace_vector& __x) + noexcept + { } + + constexpr void + clear() noexcept + { } + + constexpr friend bool + operator==(const inplace_vector&, const inplace_vector&) + { return true; } + + constexpr friend auto + operator<=>(const inplace_vector&, const inplace_vector&) + requires requires (const _Tp __t) { + { __t < __t } -> __detail::__boolean_testable; + } + { return std::strong_ordering::equal; } + + // n.b. there is not explicit wording requiring that swap for inplace_vector, + // with zero size, works even if element type is not swappable. However given + // that move operations are required to be present and trivial, it makes sense + // to support them. + constexpr friend void + swap(inplace_vector&, inplace_vector&) noexcept + { } + }; + + template<typename _Tp, size_t _Nm, typename _Predicate> + constexpr size_t + erase_if(inplace_vector<_Tp, _Nm>& __cont, _Predicate __pred) + { + using namespace __gnu_cxx; + const auto __osz = __cont.size(); + const auto __end = __cont.end(); + auto __removed = std::__remove_if(__cont.begin(), __end, + __ops::__pred_iter(std::ref(__pred))); + if (__removed != __end) + { + __cont.erase(__niter_wrap(__cont.begin(), __removed), + __cont.end()); + return __osz - __cont.size(); + } + return 0; + } + + + template<typename _Tp, size_t _Nm, typename _Up = _Tp> + constexpr size_t + erase(inplace_vector<_Tp, _Nm>& __cont, const _Up& __value) + { + using namespace __gnu_cxx; + const auto __osz = __cont.size(); + const auto __end = __cont.end(); + auto __removed = std::__remove_if(__cont.begin(), __end, + __ops::__iter_equals_val(__value)); + if (__removed != __end) + { + __cont.erase(__niter_wrap(__cont.begin(), __removed), + __cont.end()); + return __osz - __cont.size(); + } + return 0; + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // __glibcxx_inplace_vector +#endif // _GLIBCXX_INPLACE_VECTOR diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch index cf64854..9504df0 100644 --- a/libstdc++-v3/include/std/latch +++ b/libstdc++-v3/include/std/latch @@ -62,7 +62,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr explicit latch(ptrdiff_t __expected) noexcept - : _M_a(__expected) + : _M_counter(__expected) { __glibcxx_assert(__expected >= 0 && __expected <= max()); } ~latch() = default; @@ -74,35 +74,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION count_down(ptrdiff_t __update = 1) { __glibcxx_assert(__update >= 0 && __update <= max()); - auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, + auto const __old = __atomic_impl::fetch_sub(&_M_counter, __update, memory_order::release); if (std::cmp_equal(__old, __update)) - __atomic_impl::notify_all(&_M_a); + __atomic_impl::notify_all(&_M_counter); else __glibcxx_assert(std::cmp_less(__update, __old)); } _GLIBCXX_ALWAYS_INLINE bool try_wait() const noexcept - { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; } + { return __atomic_impl::load(&_M_counter, memory_order::acquire) == 0; } _GLIBCXX_ALWAYS_INLINE void wait() const noexcept { - auto const __pred = [this] { return this->try_wait(); }; - std::__atomic_wait_address(&_M_a, __pred); + auto const __vfn = [this] { + return __atomic_impl::load(&_M_counter, memory_order::acquire); + }; + auto const __pred = [](__detail::__platform_wait_t __v) { + return __v == 0; + }; + std::__atomic_wait_address(&_M_counter, __pred, __vfn); } _GLIBCXX_ALWAYS_INLINE void arrive_and_wait(ptrdiff_t __update = 1) noexcept { - count_down(__update); - wait(); + // The standard specifies this functions as count_down(update); wait(); + // but we combine those two calls into one and avoid the wait() if we + // know the counter reached zero. + + __glibcxx_assert(__update >= 0 && __update <= max()); + // Use acq_rel here because an omitted wait() would have used acquire: + auto const __old = __atomic_impl::fetch_sub(&_M_counter, __update, + memory_order::acq_rel); + if (std::cmp_equal(__old, __update)) + __atomic_impl::notify_all(&_M_counter); + else + { + __glibcxx_assert(std::cmp_less(__update, __old)); + wait(); + } } private: alignas(__detail::__platform_wait_alignment) - __detail::__platform_wait_t _M_a; + __detail::__platform_wait_t _M_counter; }; _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/std/limits b/libstdc++-v3/include/std/limits index 2331c25..49ce7c9 100644 --- a/libstdc++-v3/include/std/limits +++ b/libstdc++-v3/include/std/limits @@ -1639,7 +1639,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __INT_N_U201103(TYPE) #endif -#if !defined(__STRICT_ANSI__) #ifdef __GLIBCXX_TYPE_INT_N_0 __INT_N(__GLIBCXX_TYPE_INT_N_0, __GLIBCXX_BITSIZE_INT_N_0, __INT_N_201103 (__GLIBCXX_TYPE_INT_N_0), @@ -1661,7 +1660,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __INT_N_U201103 (__GLIBCXX_TYPE_INT_N_3)) #endif -#elif defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ +#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ __INT_N(__int128, 128, __INT_N_201103 (__int128), __INT_N_U201103 (__int128)) @@ -2129,7 +2128,7 @@ __glibcxx_float_n(128) static _GLIBCXX_USE_CONSTEXPR int digits = 113; static _GLIBCXX_USE_CONSTEXPR int digits10 = 33; #if __cplusplus >= 201103L - static constexpr int max_digits10 = 35; + static constexpr int max_digits10 = 36; #endif static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; static _GLIBCXX_USE_CONSTEXPR bool is_integer = false; diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan new file mode 100644 index 0000000..01d3b2c --- /dev/null +++ b/libstdc++-v3/include/std/mdspan @@ -0,0 +1,1543 @@ +// <mdspan> -*- C++ -*- + +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file mdspan + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_MDSPAN +#define _GLIBCXX_MDSPAN 1 + +#ifdef _GLIBCXX_SYSHDR +#pragma GCC system_header +#endif + +#include <span> +#include <array> +#include <type_traits> +#include <utility> + +#if __cplusplus > 202302L +#include <bits/align.h> +#endif + +#define __glibcxx_want_mdspan +#define __glibcxx_want_aligned_accessor +#include <bits/version.h> + +#ifdef __glibcxx_mdspan + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + namespace __mdspan + { + consteval bool + __all_static(std::span<const size_t> __extents) + { + for(auto __ext : __extents) + if (__ext == dynamic_extent) + return false; + return true; + } + + consteval bool + __all_dynamic(std::span<const size_t> __extents) + { + for(auto __ext : __extents) + if (__ext != dynamic_extent) + return false; + return true; + } + + template<array _Extents> + class _StaticExtents + { + public: + static constexpr size_t _S_rank = _Extents.size(); + + // For __r in [0, _S_rank], _S_dynamic_index(__r) is the number + // of dynamic extents up to (and not including) __r. + // + // If __r is the index of a dynamic extent, then + // _S_dynamic_index[__r] is the index of that extent in + // _M_dyn_exts. + static constexpr size_t + _S_dynamic_index(size_t __r) noexcept + { return _S_dynamic_index_data[__r]; } + + static constexpr auto _S_dynamic_index_data = [] consteval + { + array<size_t, _S_rank+1> __ret; + size_t __dyn = 0; + for (size_t __i = 0; __i < _S_rank; ++__i) + { + __ret[__i] = __dyn; + __dyn += (_Extents[__i] == dynamic_extent); + } + __ret[_S_rank] = __dyn; + return __ret; + }(); + + static constexpr size_t _S_rank_dynamic = _S_dynamic_index(_S_rank); + + // For __r in [0, _S_rank_dynamic), _S_dynamic_index_inv(__r) is the + // index of the __r-th dynamic extent in _Extents. + static constexpr size_t + _S_dynamic_index_inv(size_t __r) noexcept + { return _S_dynamic_index_inv_data[__r]; } + + static constexpr auto _S_dynamic_index_inv_data = [] consteval + { + array<size_t, _S_rank_dynamic> __ret; + for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i) + if (_Extents[__i] == dynamic_extent) + __ret[__r++] = __i; + return __ret; + }(); + + static constexpr size_t + _S_static_extent(size_t __r) noexcept + { return _Extents[__r]; } + }; + + template<array _Extents> + requires (__all_dynamic<_Extents>()) + class _StaticExtents<_Extents> + { + public: + static constexpr size_t _S_rank = _Extents.size(); + + static constexpr size_t + _S_dynamic_index(size_t __r) noexcept + { return __r; } + + static constexpr size_t _S_rank_dynamic = _S_rank; + + static constexpr size_t + _S_dynamic_index_inv(size_t __k) noexcept + { return __k; } + + static constexpr size_t + _S_static_extent(size_t) noexcept + { return dynamic_extent; } + }; + + template<typename _IndexType, array _Extents> + class _ExtentsStorage : public _StaticExtents<_Extents> + { + private: + using _Base = _StaticExtents<_Extents>; + + public: + using _Base::_S_rank; + using _Base::_S_rank_dynamic; + using _Base::_S_dynamic_index; + using _Base::_S_dynamic_index_inv; + using _Base::_S_static_extent; + + static constexpr bool + _S_is_dynamic(size_t __r) noexcept + { + if constexpr (__all_static(_Extents)) + return false; + else if constexpr (__all_dynamic(_Extents)) + return true; + else + return _Extents[__r] == dynamic_extent; + } + + template<typename _OIndexType> + static constexpr _IndexType + _S_int_cast(const _OIndexType& __other) noexcept + { return _IndexType(__other); } + + constexpr _IndexType + _M_extent(size_t __r) const noexcept + { + if (_S_is_dynamic(__r)) + return _M_dyn_exts[_S_dynamic_index(__r)]; + else + return _S_static_extent(__r); + } + + template<size_t _OtherRank, typename _GetOtherExtent> + static constexpr bool + _S_is_compatible_extents(_GetOtherExtent __get_extent) noexcept + { + if constexpr (_OtherRank == _S_rank) + for (size_t __i = 0; __i < _S_rank; ++__i) + if (!_S_is_dynamic(__i) + && !cmp_equal(_Extents[__i], _S_int_cast(__get_extent(__i)))) + return false; + return true; + } + + template<size_t _OtherRank, typename _GetOtherExtent> + constexpr void + _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept + { + __glibcxx_assert(_S_is_compatible_extents<_OtherRank>(__get_extent)); + for (size_t __i = 0; __i < _S_rank_dynamic; ++__i) + { + size_t __di = __i; + if constexpr (_OtherRank != _S_rank_dynamic) + __di = _S_dynamic_index_inv(__i); + _M_dyn_exts[__i] = _S_int_cast(__get_extent(__di)); + } + } + + constexpr + _ExtentsStorage() noexcept = default; + + template<typename _OIndexType, array _OExtents> + constexpr + _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>& + __other) noexcept + { + _M_init_dynamic_extents<_S_rank>([&__other](size_t __i) + { return __other._M_extent(__i); }); + } + + template<typename _OIndexType, size_t _Nm> + constexpr + _ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept + { + _M_init_dynamic_extents<_Nm>( + [&__exts](size_t __i) -> const _OIndexType& + { return __exts[__i]; }); + } + + static constexpr const array<size_t, _S_rank>& + _S_static_extents() noexcept + { return _Extents; } + + constexpr span<const _IndexType> + _M_dynamic_extents(size_t __begin, size_t __end) const noexcept + requires (_Extents.size() > 0) + { + return {_M_dyn_exts + _S_dynamic_index(__begin), + _M_dyn_exts + _S_dynamic_index(__end)}; + } + + private: + using _Storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type; + [[no_unique_address]] _Storage _M_dyn_exts{}; + }; + + template<typename _OIndexType, typename _SIndexType> + concept __valid_index_type = + is_convertible_v<_OIndexType, _SIndexType> && + is_nothrow_constructible_v<_SIndexType, _OIndexType>; + + template<size_t _Extent, typename _IndexType> + concept + __valid_static_extent = _Extent == dynamic_extent + || _Extent <= __gnu_cxx::__int_traits<_IndexType>::__max; + + template<typename _Extents> + constexpr const array<size_t, _Extents::rank()>& + __static_extents() noexcept + { return _Extents::_Storage::_S_static_extents(); } + + // Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n (exclusive) + template<array _Extents> + constexpr auto __fwd_partial_prods = [] consteval + { + constexpr size_t __rank = _Extents.size(); + std::array<size_t, __rank> __ret; + size_t __prod = 1; + for (size_t __r = 0; __r < __rank; ++__r) + { + __ret[__r] = __prod; + if (size_t __ext = _Extents[__r]; __ext != dynamic_extent) + __prod *= __ext; + } + return __ret; + }(); + + // Pre-compute: \prod_{i = r+1}^{n-1} _Extents[i] + template<array _Extents> + constexpr auto __rev_partial_prods = [] consteval + { + constexpr size_t __rank = _Extents.size(); + std::array<size_t, __rank> __ret; + size_t __prod = 1; + for (size_t __r = __rank; __r > 0; --__r) + { + __ret[__r - 1] = __prod; + if (size_t __ext = _Extents[__r - 1]; __ext != dynamic_extent) + __prod *= __ext; + } + return __ret; + }(); + + template<typename _Extents> + constexpr span<const typename _Extents::index_type> + __dynamic_extents(const _Extents& __exts, size_t __begin = 0, + size_t __end = _Extents::rank()) noexcept + { return __exts._M_exts._M_dynamic_extents(__begin, __end); } + } + + template<typename _IndexType, size_t... _Extents> + class extents + { + static_assert(__is_standard_integer<_IndexType>::value, + "IndexType must be a signed or unsigned integer type"); + static_assert( + (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...), + "Extents must either be dynamic or representable as IndexType"); + public: + using index_type = _IndexType; + using size_type = make_unsigned_t<index_type>; + using rank_type = size_t; + + static constexpr rank_type + rank() noexcept { return _Storage::_S_rank; } + + static constexpr rank_type + rank_dynamic() noexcept { return _Storage::_S_rank_dynamic; } + + static constexpr size_t + static_extent(rank_type __r) noexcept + { + __glibcxx_assert(__r < rank()); + if constexpr (rank() == 0) + __builtin_trap(); + else + return _Storage::_S_static_extent(__r); + } + + constexpr index_type + extent(rank_type __r) const noexcept + { + __glibcxx_assert(__r < rank()); + if constexpr (rank() == 0) + __builtin_trap(); + else + return _M_exts._M_extent(__r); + } + + constexpr + extents() noexcept = default; + + private: + static consteval bool + _S_is_less_dynamic(size_t __ext, size_t __oext) + { return (__ext != dynamic_extent) && (__oext == dynamic_extent); } + + template<typename _OIndexType, size_t... _OExtents> + static consteval bool + _S_ctor_explicit() + { + return (_S_is_less_dynamic(_Extents, _OExtents) || ...) + || (__gnu_cxx::__int_traits<index_type>::__max + < __gnu_cxx::__int_traits<_OIndexType>::__max); + } + + template<size_t... _OExtents> + static consteval bool + _S_is_compatible_extents() + { + if constexpr (sizeof...(_OExtents) != rank()) + return false; + else + return ((_OExtents == dynamic_extent || _Extents == dynamic_extent + || _OExtents == _Extents) && ...); + } + + public: + template<typename _OIndexType, size_t... _OExtents> + requires (_S_is_compatible_extents<_OExtents...>()) + constexpr explicit(_S_ctor_explicit<_OIndexType, _OExtents...>()) + extents(const extents<_OIndexType, _OExtents...>& __other) noexcept + : _M_exts(__other._M_exts) + { } + + template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> + requires (sizeof...(_OIndexTypes) == rank() + || sizeof...(_OIndexTypes) == rank_dynamic()) + constexpr explicit extents(_OIndexTypes... __exts) noexcept + : _M_exts(span<const _IndexType, sizeof...(_OIndexTypes)>( + initializer_list{static_cast<_IndexType>(std::move(__exts))...})) + { } + + template<typename _OIndexType, size_t _Nm> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + && (_Nm == rank() || _Nm == rank_dynamic()) + constexpr explicit(_Nm != rank_dynamic()) + extents(span<_OIndexType, _Nm> __exts) noexcept + : _M_exts(span<const _OIndexType, _Nm>(__exts)) + { } + + template<typename _OIndexType, size_t _Nm> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + && (_Nm == rank() || _Nm == rank_dynamic()) + constexpr explicit(_Nm != rank_dynamic()) + extents(const array<_OIndexType, _Nm>& __exts) noexcept + : _M_exts(span<const _OIndexType, _Nm>(__exts)) + { } + + template<typename _OIndexType, size_t... _OExtents> + friend constexpr bool + operator==(const extents& __self, + const extents<_OIndexType, _OExtents...>& __other) noexcept + { + if constexpr (!_S_is_compatible_extents<_OExtents...>()) + return false; + else + { + auto __impl = [&__self, &__other]<size_t... _Counts>( + index_sequence<_Counts...>) + { return (cmp_equal(__self.extent(_Counts), + __other.extent(_Counts)) && ...); }; + return __impl(make_index_sequence<__self.rank()>()); + } + } + + private: + friend const array<size_t, rank()>& + __mdspan::__static_extents<extents>(); + + friend span<const index_type> + __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t); + + using _Storage = __mdspan::_ExtentsStorage< + _IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>; + [[no_unique_address]] _Storage _M_exts; + + template<typename _OIndexType, size_t... _OExtents> + friend class extents; + }; + + namespace __mdspan + { + template<typename _Tp, size_t _Nm> + constexpr bool + __contains_zero(span<_Tp, _Nm> __exts) noexcept + { + for (size_t __i = 0; __i < __exts.size(); ++__i) + if (__exts[__i] == 0) + return true; + return false; + } + + template<typename _Tp, size_t _Nm> + consteval bool + __contains_zero(const array<_Tp, _Nm>& __exts) noexcept + { return __contains_zero(span<const _Tp>(__exts)); } + + template<typename _Extents> + constexpr bool + __empty(const _Extents& __exts) noexcept + { + if constexpr (__contains_zero(__static_extents<_Extents>())) + return true; + else if constexpr (_Extents::rank_dynamic() > 0) + return __contains_zero(__dynamic_extents(__exts)); + else + return false; + } + + template<typename _Extents> + constexpr typename _Extents::index_type + __extents_prod(const _Extents& __exts, size_t __sta_prod, size_t __begin, + size_t __end) noexcept + { + if (__sta_prod == 0) + return 0; + + size_t __ret = __sta_prod; + if constexpr (_Extents::rank_dynamic() > 0) + for (auto __factor : __dynamic_extents(__exts, __begin, __end)) + __ret *= size_t(__factor); + return static_cast<typename _Extents::index_type>(__ret); + } + + // Preconditions: _r < _Extents::rank() + template<typename _Extents> + constexpr typename _Extents::index_type + __fwd_prod(const _Extents& __exts, size_t __r) noexcept + { + constexpr size_t __rank = _Extents::rank(); + constexpr auto& __sta_exts = __static_extents<_Extents>(); + if constexpr (__rank == 1) + return 1; + else if constexpr (__rank == 2) + return __r == 0 ? 1 : __exts.extent(0); + else if constexpr (__all_dynamic(std::span(__sta_exts).first(__rank-1))) + return __extents_prod(__exts, 1, 0, __r); + else + { + size_t __sta_prod = __fwd_partial_prods<__sta_exts>[__r]; + return __extents_prod(__exts, __sta_prod, 0, __r); + } + } + + // Preconditions: _r < _Extents::rank() + template<typename _Extents> + constexpr typename _Extents::index_type + __rev_prod(const _Extents& __exts, size_t __r) noexcept + { + constexpr size_t __rank = _Extents::rank(); + constexpr auto& __sta_exts = __static_extents<_Extents>(); + if constexpr (__rank == 1) + return 1; + else if constexpr (__rank == 2) + return __r == 0 ? __exts.extent(1) : 1; + else if constexpr (__all_dynamic(std::span(__sta_exts).last(__rank-1))) + return __extents_prod(__exts, 1, __r + 1, __rank); + else + { + size_t __sta_prod = __rev_partial_prods<__sta_exts>[__r]; + return __extents_prod(__exts, __sta_prod, __r + 1, __rank); + } + } + + template<typename _Extents> + constexpr typename _Extents::index_type + __size(const _Extents& __exts) noexcept + { + constexpr size_t __sta_prod = [] { + span<const size_t> __sta_exts = __static_extents<_Extents>(); + size_t __ret = 1; + for(auto __ext : __sta_exts) + if (__ext != dynamic_extent) + __ret *= __ext; + return __ret; + }(); + return __extents_prod(__exts, __sta_prod, 0, _Extents::rank()); + } + + template<typename _IndexType, size_t... _Counts> + auto __build_dextents_type(integer_sequence<size_t, _Counts...>) + -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>; + } + + template<typename _IndexType, size_t _Rank> + using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>( + make_index_sequence<_Rank>())); + +#if __glibcxx_mdspan >= 202406L + template<size_t _Rank, typename _IndexType = size_t> + using dims = dextents<_IndexType, _Rank>; +#endif + + template<typename... _Integrals> + requires (is_convertible_v<_Integrals, size_t> && ...) + explicit extents(_Integrals...) -> + extents<size_t, __detail::__maybe_static_ext<_Integrals>...>; + + struct layout_left + { + template<typename _Extents> + class mapping; + }; + + struct layout_right + { + template<typename _Extents> + class mapping; + }; + + struct layout_stride + { + template<typename _Extents> + class mapping; + }; + + namespace __mdspan + { + template<typename _Tp> + constexpr bool __is_extents = false; + + template<typename _IndexType, size_t... _Extents> + constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true; + + template<typename _Extents, typename... _Indices> + constexpr typename _Extents::index_type + __linear_index_left(const _Extents& __exts, _Indices... __indices) + noexcept + { + using _IndexType = typename _Extents::index_type; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + _IndexType __mult = 1; + auto __update = [&, __pos = 0u](_IndexType __idx) mutable + { + _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __exts.extent(__pos))); + __res += __idx * __mult; + __mult *= __exts.extent(__pos); + ++__pos; + }; + (__update(__indices), ...); + } + return __res; + } + + template<typename _Extents, + typename _IndexType = typename _Extents::index_type> + consteval _IndexType + __static_quotient(_IndexType __nom = __gnu_cxx::__int_traits<_IndexType> + ::__max) + { + std::span<const size_t> __sta_exts = __static_extents<_Extents>(); + for (auto __factor : __sta_exts) + { + if (__factor != dynamic_extent) + __nom /= _IndexType(__factor); + if (__nom == 0) + break; + } + return __nom; + } + + template<typename _Extents> + constexpr bool + __is_representable_extents(const _Extents& __exts) noexcept + { + using _IndexType = _Extents::index_type; + + if constexpr (__contains_zero(__static_extents<_Extents>())) + return true; + else + { + constexpr auto __sta_quo = __static_quotient<_Extents>(); + if constexpr (_Extents::rank_dynamic() == 0) + return __sta_quo != 0; + else + { + auto __dyn_exts = __dynamic_extents(__exts); + if (__contains_zero(__dyn_exts)) + return true; + + if constexpr (__sta_quo == 0) + return false; + else + { + auto __dyn_quo = _IndexType(__sta_quo); + for (auto __factor : __dyn_exts) + { + __dyn_quo /= __factor; + if (__dyn_quo == 0) + return false; + } + return true; + } + } + } + } + + template<typename _Extents, typename _IndexType> + concept __representable_size = _Extents::rank_dynamic() != 0 + || __contains_zero(__static_extents<_Extents>()) + || (__static_quotient<_Extents, _IndexType>() != 0); + + template<typename _Layout, typename _Mapping> + concept __mapping_of = + is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>, + _Mapping>; + + template<typename _Mapping> + concept __standardized_mapping = __mapping_of<layout_left, _Mapping> + || __mapping_of<layout_right, _Mapping> + || __mapping_of<layout_stride, _Mapping>; + + // A tag type to create internal ctors. + class __internal_ctor + { }; + } + + template<typename _Extents> + class layout_left::mapping + { + public: + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_left; + + static_assert(__mdspan::__representable_size<extents_type, index_type>, + "The size of extents_type must be representable as index_type"); + + constexpr + mapping() noexcept = default; + + constexpr + mapping(const mapping&) noexcept = default; + + constexpr + mapping(const extents_type& __extents) noexcept + : _M_extents(__extents) + { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + template<typename _OExtents> + requires (extents_type::rank() <= 1) + && is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const layout_right::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + // noexcept for consistency with other layouts. + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { __glibcxx_assert(*this == __other); } + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_extents; } + + constexpr index_type + required_span_size() const noexcept + { return __mdspan::__size(_M_extents); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4314. Missing move in mdspan layout mapping::operator() + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == extents_type::rank()) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_left(_M_extents, + static_cast<index_type>(std::move(__indices))...); + } + + static constexpr bool + is_always_unique() noexcept { return true; } + + static constexpr bool + is_always_exhaustive() noexcept { return true; } + + static constexpr bool + is_always_strided() noexcept { return true; } + + static constexpr bool + is_unique() noexcept { return true; } + + static constexpr bool + is_exhaustive() noexcept { return true; } + + static constexpr bool + is_strided() noexcept { return true; } + + constexpr index_type + stride(rank_type __i) const noexcept + requires (extents_type::rank() > 0) + { + __glibcxx_assert(__i < extents_type::rank()); + return __mdspan::__fwd_prod(_M_extents, __i); + } + + template<typename _OExtents> + requires (extents_type::rank() == _OExtents::rank()) + friend constexpr bool + operator==(const mapping& __self, const mapping<_OExtents>& __other) + noexcept + { return __self.extents() == __other.extents(); } + + private: + template<typename _OExtents> + constexpr explicit + mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept + : _M_extents(__oexts) + { + static_assert(__mdspan::__representable_size<_OExtents, index_type>, + "The size of OtherExtents must be representable as index_type"); + __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); + } + + [[no_unique_address]] extents_type _M_extents{}; + }; + + namespace __mdspan + { + template<typename _Extents, typename... _Indices> + constexpr typename _Extents::index_type + __linear_index_right(const _Extents& __exts, _Indices... __indices) + noexcept + { + using _IndexType = typename _Extents::index_type; + array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...}; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + _IndexType __mult = 1; + auto __update = [&, __pos = __exts.rank()](_IndexType) mutable + { + --__pos; + _GLIBCXX_DEBUG_ASSERT(cmp_less(__ind_arr[__pos], + __exts.extent(__pos))); + __res += __ind_arr[__pos] * __mult; + __mult *= __exts.extent(__pos); + }; + (__update(__indices), ...); + } + return __res; + } + } + + template<typename _Extents> + class layout_right::mapping + { + public: + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_right; + + static_assert(__mdspan::__representable_size<extents_type, index_type>, + "The size of extents_type must be representable as index_type"); + + constexpr + mapping() noexcept = default; + + constexpr + mapping(const mapping&) noexcept = default; + + constexpr + mapping(const extents_type& __extents) noexcept + : _M_extents(__extents) + { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + template<typename _OExtents> + requires (extents_type::rank() <= 1) + && is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const layout_left::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { __glibcxx_assert(*this == __other); } + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_extents; } + + constexpr index_type + required_span_size() const noexcept + { return __mdspan::__size(_M_extents); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4314. Missing move in mdspan layout mapping::operator() + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == extents_type::rank()) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_right( + _M_extents, static_cast<index_type>(std::move(__indices))...); + } + + static constexpr bool + is_always_unique() noexcept + { return true; } + + static constexpr bool + is_always_exhaustive() noexcept + { return true; } + + static constexpr bool + is_always_strided() noexcept + { return true; } + + static constexpr bool + is_unique() noexcept + { return true; } + + static constexpr bool + is_exhaustive() noexcept + { return true; } + + static constexpr bool + is_strided() noexcept + { return true; } + + constexpr index_type + stride(rank_type __i) const noexcept + requires (extents_type::rank() > 0) + { + __glibcxx_assert(__i < extents_type::rank()); + return __mdspan::__rev_prod(_M_extents, __i); + } + + template<typename _OExtents> + requires (extents_type::rank() == _OExtents::rank()) + friend constexpr bool + operator==(const mapping& __self, const mapping<_OExtents>& __other) + noexcept + { return __self.extents() == __other.extents(); } + + private: + template<typename _OExtents> + constexpr explicit + mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept + : _M_extents(__oexts) + { + static_assert(__mdspan::__representable_size<_OExtents, index_type>, + "The size of OtherExtents must be representable as index_type"); + __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); + } + + [[no_unique_address]] extents_type _M_extents{}; + }; + + namespace __mdspan + { + template<typename _Mp> + concept __mapping_alike = requires + { + requires __is_extents<typename _Mp::extents_type>; + { _Mp::is_always_strided() } -> same_as<bool>; + { _Mp::is_always_exhaustive() } -> same_as<bool>; + { _Mp::is_always_unique() } -> same_as<bool>; + bool_constant<_Mp::is_always_strided()>::value; + bool_constant<_Mp::is_always_exhaustive()>::value; + bool_constant<_Mp::is_always_unique()>::value; + }; + + template<typename _Mapping> + constexpr typename _Mapping::index_type + __offset(const _Mapping& __m) noexcept + { + using _IndexType = typename _Mapping::index_type; + constexpr auto __rank = _Mapping::extents_type::rank(); + + if constexpr (__standardized_mapping<_Mapping>) + return 0; + else if (__empty(__m.extents())) + return 0; + else + { + auto __impl = [&__m]<size_t... _Counts>(index_sequence<_Counts...>) + { return __m(((void) _Counts, _IndexType(0))...); }; + return __impl(make_index_sequence<__rank>()); + } + } + + template<typename _Mapping, typename... _Indices> + constexpr typename _Mapping::index_type + __linear_index_strides(const _Mapping& __m, _Indices... __indices) + noexcept + { + using _IndexType = typename _Mapping::index_type; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + auto __update = [&, __pos = 0u](_IndexType __idx) mutable + { + _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, + __m.extents().extent(__pos))); + __res += __idx * __m.stride(__pos++); + }; + (__update(__indices), ...); + } + return __res; + } + } + + template<typename _Extents> + class layout_stride::mapping + { + public: + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_stride; + + static_assert(__mdspan::__representable_size<extents_type, index_type>, + "The size of extents_type must be representable as index_type"); + + constexpr + mapping() noexcept + { + // The precondition is either statically asserted, or automatically + // satisfied because dynamic extents are zero-initialized. + size_t __stride = 1; + for (size_t __i = extents_type::rank(); __i > 0; --__i) + { + _M_strides[__i - 1] = index_type(__stride); + __stride *= size_t(_M_extents.extent(__i - 1)); + } + } + + constexpr + mapping(const mapping&) noexcept = default; + + template<typename _OIndexType> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + constexpr + mapping(const extents_type& __exts, + span<_OIndexType, extents_type::rank()> __strides) noexcept + : _M_extents(__exts) + { + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + _M_strides[__i] = index_type(as_const(__strides[__i])); + } + + template<typename _OIndexType> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + constexpr + mapping(const extents_type& __exts, + const array<_OIndexType, extents_type::rank()>& __strides) + noexcept + : mapping(__exts, + span<const _OIndexType, extents_type::rank()>(__strides)) + { } + + template<__mdspan::__mapping_alike _StridedMapping> + requires (is_constructible_v<extents_type, + typename _StridedMapping::extents_type> + && _StridedMapping::is_always_unique() + && _StridedMapping::is_always_strided()) + constexpr explicit(!( + is_convertible_v<typename _StridedMapping::extents_type, extents_type> + && __mdspan::__standardized_mapping<_StridedMapping>)) + mapping(const _StridedMapping& __other) noexcept + : _M_extents(__other.extents()) + { + using _OIndexType = _StridedMapping::index_type; + using _OExtents = _StridedMapping::extents_type; + + __glibcxx_assert(__mdspan::__offset(__other) == 0); + static_assert(__mdspan::__representable_size<_OExtents, index_type>, + "The size of StridedMapping::extents_type must be representable as" + " index_type"); + if constexpr (cmp_greater(__gnu_cxx::__int_traits<_OIndexType>::__max, + __gnu_cxx::__int_traits<index_type>::__max)) + __glibcxx_assert(!cmp_less( + __gnu_cxx::__int_traits<index_type>::__max, + __other.required_span_size()) + && "other.required_span_size() must be representable" + " as index_type"); + if constexpr (extents_type::rank() > 0) + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + _M_strides[__i] = index_type(__other.stride(__i)); + } + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_extents; } + + constexpr array<index_type, extents_type::rank()> + strides() const noexcept + { + array<index_type, extents_type::rank()> __ret; + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + __ret[__i] = _M_strides[__i]; + return __ret; + } + + constexpr index_type + required_span_size() const noexcept + { + if (__mdspan::__empty(_M_extents)) + return 0; + + index_type __ret = 1; + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + __ret += (_M_extents.extent(__i) - 1) * _M_strides[__i]; + return __ret; + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4314. Missing move in mdspan layout mapping::operator() + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == extents_type::rank()) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_strides(*this, + static_cast<index_type>(std::move(__indices))...); + } + + static constexpr bool + is_always_unique() noexcept { return true; } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4266. layout_stride::mapping should treat empty mappings as exhaustive + static constexpr bool + is_always_exhaustive() noexcept + { + return (_Extents::rank() == 0) || __mdspan::__contains_zero( + __mdspan::__static_extents<extents_type>()); + } + + static constexpr bool + is_always_strided() noexcept { return true; } + + static constexpr bool + is_unique() noexcept { return true; } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4266. layout_stride::mapping should treat empty mappings as exhaustive + constexpr bool + is_exhaustive() const noexcept + { + if constexpr (!is_always_exhaustive()) + { + auto __size = __mdspan::__size(_M_extents); + if(__size > 0) + return __size == required_span_size(); + } + return true; + } + + static constexpr bool + is_strided() noexcept { return true; } + + constexpr index_type + stride(rank_type __r) const noexcept { return _M_strides[__r]; } + + template<__mdspan::__mapping_alike _OMapping> + requires ((extents_type::rank() == _OMapping::extents_type::rank()) + && _OMapping::is_always_strided()) + friend constexpr bool + operator==(const mapping& __self, const _OMapping& __other) noexcept + { + if (__self.extents() != __other.extents()) + return false; + if constexpr (extents_type::rank() > 0) + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + if (!cmp_equal(__self.stride(__i), __other.stride(__i))) + return false; + return __mdspan::__offset(__other) == 0; + } + + private: + using _Strides = typename __array_traits<index_type, + extents_type::rank()>::_Type; + [[no_unique_address]] extents_type _M_extents; + [[no_unique_address]] _Strides _M_strides; + }; + + template<typename _ElementType> + struct default_accessor + { + static_assert(!is_array_v<_ElementType>, + "ElementType must not be an array type"); + static_assert(!is_abstract_v<_ElementType>, + "ElementType must not be an abstract class type"); + + using offset_policy = default_accessor; + using element_type = _ElementType; + using reference = element_type&; + using data_handle_type = element_type*; + + constexpr + default_accessor() noexcept = default; + + template<typename _OElementType> + requires is_convertible_v<_OElementType(*)[], element_type(*)[]> + constexpr + default_accessor(default_accessor<_OElementType>) noexcept + { } + + constexpr reference + access(data_handle_type __p, size_t __i) const noexcept + { return __p[__i]; } + + constexpr data_handle_type + offset(data_handle_type __p, size_t __i) const noexcept + { return __p + __i; } + }; + +#ifdef __glibcxx_aligned_accessor + template<typename _ElementType, size_t _ByteAlignment> + struct aligned_accessor + { + static_assert(has_single_bit(_ByteAlignment), + "ByteAlignment must be a power of two"); + static_assert(_ByteAlignment >= alignof(_ElementType)); + + using offset_policy = default_accessor<_ElementType>; + using element_type = _ElementType; + using reference = element_type&; + using data_handle_type = element_type*; + + static constexpr size_t byte_alignment = _ByteAlignment; + + constexpr + aligned_accessor() noexcept = default; + + template<typename _OElementType, size_t _OByteAlignment> + requires (_OByteAlignment >= byte_alignment) + && is_convertible_v<_OElementType(*)[], element_type(*)[]> + constexpr + aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>) + noexcept + { } + + template<typename _OElementType> + requires is_convertible_v<_OElementType(*)[], element_type(*)[]> + constexpr explicit + aligned_accessor(default_accessor<_OElementType>) noexcept + { } + + template<typename _OElementType> + requires is_convertible_v<element_type(*)[], _OElementType(*)[]> + constexpr + operator default_accessor<_OElementType>() const noexcept + { return {}; } + + constexpr reference + access(data_handle_type __p, size_t __i) const noexcept + { return std::assume_aligned<byte_alignment>(__p)[__i]; } + + constexpr typename offset_policy::data_handle_type + offset(data_handle_type __p, size_t __i) const noexcept + { return std::assume_aligned<byte_alignment>(__p) + __i; } + }; +#endif + + namespace __mdspan + { + template<typename _Extents, typename _IndexType, size_t _Nm> + constexpr bool + __is_multi_index(const _Extents& __exts, span<_IndexType, _Nm> __indices) + { + static_assert(__exts.rank() == _Nm); + for (size_t __i = 0; __i < __exts.rank(); ++__i) + if (__indices[__i] >= __exts.extent(__i)) + return false; + return true; + } + } + + template<typename _ElementType, typename _Extents, + typename _LayoutPolicy = layout_right, + typename _AccessorPolicy = default_accessor<_ElementType>> + class mdspan + { + static_assert(!is_array_v<_ElementType>, + "ElementType must not be an array type"); + static_assert(!is_abstract_v<_ElementType>, + "ElementType must not be an abstract class type"); + static_assert(__mdspan::__is_extents<_Extents>, + "Extents must be a specialization of std::extents"); + static_assert(is_same_v<_ElementType, + typename _AccessorPolicy::element_type>); + + public: + using extents_type = _Extents; + using layout_type = _LayoutPolicy; + using accessor_type = _AccessorPolicy; + using mapping_type = typename layout_type::template mapping<extents_type>; + using element_type = _ElementType; + using value_type = remove_cv_t<element_type>; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using data_handle_type = typename accessor_type::data_handle_type; + using reference = typename accessor_type::reference; + + static constexpr rank_type + rank() noexcept { return extents_type::rank(); } + + static constexpr rank_type + rank_dynamic() noexcept { return extents_type::rank_dynamic(); } + + static constexpr size_t + static_extent(rank_type __r) noexcept + { return extents_type::static_extent(__r); } + + constexpr index_type + extent(rank_type __r) const noexcept { return extents().extent(__r); } + + constexpr + mdspan() + requires (rank_dynamic() > 0) + && is_default_constructible_v<data_handle_type> + && is_default_constructible_v<mapping_type> + && is_default_constructible_v<accessor_type> = default; + + constexpr + mdspan(const mdspan& __other) = default; + + constexpr + mdspan(mdspan&& __other) = default; + + template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> + requires (sizeof...(_OIndexTypes) == rank() + || sizeof...(_OIndexTypes) == rank_dynamic()) + && is_constructible_v<mapping_type, extents_type> + && is_default_constructible_v<accessor_type> + constexpr explicit + mdspan(data_handle_type __handle, _OIndexTypes... __exts) + : _M_accessor(), + _M_mapping(_Extents(static_cast<index_type>(std::move(__exts))...)), + _M_handle(std::move(__handle)) + { } + + template<typename _OIndexType, size_t _Nm> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + && (_Nm == rank() || _Nm == rank_dynamic()) + && is_constructible_v<mapping_type, extents_type> + && is_default_constructible_v<accessor_type> + constexpr explicit(_Nm != rank_dynamic()) + mdspan(data_handle_type __handle, span<_OIndexType, _Nm> __exts) + : _M_accessor(), _M_mapping(extents_type(__exts)), + _M_handle(std::move(__handle)) + { } + + template<typename _OIndexType, size_t _Nm> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + && (_Nm == rank() || _Nm == rank_dynamic()) + && is_constructible_v<mapping_type, extents_type> + && is_default_constructible_v<accessor_type> + constexpr explicit(_Nm != rank_dynamic()) + mdspan(data_handle_type __handle, const array<_OIndexType, _Nm>& __exts) + : _M_accessor(), _M_mapping(extents_type(__exts)), + _M_handle(std::move(__handle)) + { } + + constexpr + mdspan(data_handle_type __handle, const extents_type& __exts) + requires is_constructible_v<mapping_type, const extents_type&> + && is_default_constructible_v<accessor_type> + : _M_accessor(), _M_mapping(__exts), _M_handle(std::move(__handle)) + { } + + constexpr + mdspan(data_handle_type __handle, const mapping_type& __mapping) + requires is_default_constructible_v<accessor_type> + : _M_accessor(), _M_mapping(__mapping), _M_handle(std::move(__handle)) + { } + + constexpr + mdspan(data_handle_type __handle, const mapping_type& __mapping, + const accessor_type& __accessor) + : _M_accessor(__accessor), _M_mapping(__mapping), + _M_handle(std::move(__handle)) + { } + + template<typename _OElementType, typename _OExtents, typename _OLayout, + typename _OAccessor> + requires is_constructible_v<mapping_type, + const typename _OLayout::template mapping<_OExtents>&> + && is_constructible_v<accessor_type, const _OAccessor&> + constexpr explicit(!is_convertible_v< + const typename _OLayout::template mapping<_OExtents>&, mapping_type> + || !is_convertible_v<const _OAccessor&, accessor_type>) + mdspan(const mdspan<_OElementType, _OExtents, _OLayout, _OAccessor>& + __other) + : _M_accessor(__other.accessor()), _M_mapping(__other.mapping()), + _M_handle(__other.data_handle()) + { + static_assert(is_constructible_v<data_handle_type, + const typename _OAccessor::data_handle_type&>); + static_assert(is_constructible_v<extents_type, _OExtents>); + } + + constexpr mdspan& + operator=(const mdspan& __other) = default; + + constexpr mdspan& + operator=(mdspan&& __other) = default; + + template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> + requires (sizeof...(_OIndexTypes) == rank()) + constexpr reference + operator[](_OIndexTypes... __indices) const + { + auto __checked_call = [this](auto... __idxs) -> index_type + { + if constexpr (sizeof...(__idxs) > 0) + __glibcxx_assert(__mdspan::__is_multi_index(extents(), + span<const index_type, sizeof...(__idxs)>({__idxs...}))); + return _M_mapping(__idxs...); + }; + + auto __index = __checked_call( + static_cast<index_type>(std::move(__indices))...); + return _M_accessor.access(_M_handle, __index); + } + + template<typename _OIndexType> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + constexpr reference + operator[](span<_OIndexType, rank()> __indices) const + { + auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>) + -> reference + { return (*this)[index_type(as_const(__indices[_Counts]))...]; }; + return __call(make_index_sequence<rank()>()); + } + + template<typename _OIndexType> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + constexpr reference + operator[](const array<_OIndexType, rank()>& __indices) const + { return (*this)[span<const _OIndexType, rank()>(__indices)]; } + + constexpr size_type + size() const noexcept + { + __glibcxx_assert(cmp_less_equal(_M_mapping.required_span_size(), + __gnu_cxx::__int_traits<size_t> + ::__max)); + return size_type(__mdspan::__size(extents())); + } + + [[nodiscard]] + constexpr bool + empty() const noexcept + { return __mdspan::__empty(extents()); } + + friend constexpr void + swap(mdspan& __x, mdspan& __y) noexcept + { + using std::swap; + swap(__x._M_mapping, __y._M_mapping); + swap(__x._M_accessor, __y._M_accessor); + swap(__x._M_handle, __y._M_handle); + } + + constexpr const extents_type& + extents() const noexcept { return _M_mapping.extents(); } + + constexpr const data_handle_type& + data_handle() const noexcept { return _M_handle; } + + constexpr const mapping_type& + mapping() const noexcept { return _M_mapping; } + + constexpr const accessor_type& + accessor() const noexcept { return _M_accessor; } + + // Strengthened noexcept for all `is_*` methods. + + static constexpr bool + is_always_unique() noexcept(noexcept(mapping_type::is_always_unique())) + { return mapping_type::is_always_unique(); } + + static constexpr bool + is_always_exhaustive() + noexcept(noexcept(mapping_type::is_always_exhaustive())) + { return mapping_type::is_always_exhaustive(); } + + static constexpr bool + is_always_strided() + noexcept(noexcept(mapping_type::is_always_strided())) + { return mapping_type::is_always_strided(); } + + constexpr bool + is_unique() const noexcept(noexcept(_M_mapping.is_unique())) + { return _M_mapping.is_unique(); } + + constexpr bool + is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive())) + { return _M_mapping.is_exhaustive(); } + + constexpr bool + is_strided() const noexcept(noexcept(_M_mapping.is_strided())) + { return _M_mapping.is_strided(); } + + constexpr index_type + stride(rank_type __r) const { return _M_mapping.stride(__r); } + + private: + [[no_unique_address]] accessor_type _M_accessor = accessor_type(); + [[no_unique_address]] mapping_type _M_mapping = mapping_type(); + [[no_unique_address]] data_handle_type _M_handle = data_handle_type(); + }; + + template<typename _CArray> + requires is_array_v<_CArray> && (rank_v<_CArray> == 1) + mdspan(_CArray&) + -> mdspan<remove_all_extents_t<_CArray>, + extents<size_t, extent_v<_CArray, 0>>>; + + template<typename _Pointer> + requires is_pointer_v<remove_reference_t<_Pointer>> + mdspan(_Pointer&&) + -> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>; + + template<typename _ElementType, typename... _Integrals> + requires (is_convertible_v<_Integrals, size_t> && ...) + && (sizeof...(_Integrals) > 0) + explicit mdspan(_ElementType*, _Integrals...) + -> mdspan<_ElementType, + extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>; + + template<typename _ElementType, typename _OIndexType, size_t _Nm> + mdspan(_ElementType*, span<_OIndexType, _Nm>) + -> mdspan<_ElementType, dextents<size_t, _Nm>>; + + template<typename _ElementType, typename _OIndexType, size_t _Nm> + mdspan(_ElementType*, const array<_OIndexType, _Nm>&) + -> mdspan<_ElementType, dextents<size_t, _Nm>>; + + template<typename _ElementType, typename _IndexType, size_t... _ExtentsPack> + mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&) + -> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>; + + template<typename _ElementType, typename _MappingType> + mdspan(_ElementType*, const _MappingType&) + -> mdspan<_ElementType, typename _MappingType::extents_type, + typename _MappingType::layout_type>; + + template<typename _MappingType, typename _AccessorType> + mdspan(const typename _AccessorType::data_handle_type&, const _MappingType&, + const _AccessorType&) + -> mdspan<typename _AccessorType::element_type, + typename _MappingType::extents_type, + typename _MappingType::layout_type, _AccessorType>; + +_GLIBCXX_END_NAMESPACE_VERSION +} +#endif +#endif diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory index 99f542d..bc59622 100644 --- a/libstdc++-v3/include/std/memory +++ b/libstdc++-v3/include/std/memory @@ -97,6 +97,11 @@ # include <bits/out_ptr.h> #endif +#if __cplusplus > 202302L +# include <bits/indirect.h> +#endif + +#define __glibcxx_want_addressof_constexpr #define __glibcxx_want_allocator_traits_is_always_equal #define __glibcxx_want_assume_aligned #define __glibcxx_want_atomic_shared_ptr @@ -104,9 +109,12 @@ #define __glibcxx_want_constexpr_dynamic_alloc #define __glibcxx_want_constexpr_memory #define __glibcxx_want_enable_shared_from_this +#define __glibcxx_want_indirect +#define __glibcxx_want_is_sufficiently_aligned #define __glibcxx_want_make_unique #define __glibcxx_want_out_ptr #define __glibcxx_want_parallel_algorithm +#define __glibcxx_want_polymorphic #define __glibcxx_want_ranges #define __glibcxx_want_raw_memory_algorithms #define __glibcxx_want_shared_ptr_arrays @@ -114,6 +122,7 @@ #define __glibcxx_want_smart_ptr_for_overwrite #define __glibcxx_want_to_address #define __glibcxx_want_transparent_operators +#define __glibcxx_want_smart_ptr_owner_equality #include <bits/version.h> #if __cplusplus >= 201103L && __cplusplus <= 202002L && _GLIBCXX_HOSTED diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex index b3f89c0..631c380 100644 --- a/libstdc++-v3/include/std/mutex +++ b/libstdc++-v3/include/std/mutex @@ -190,7 +190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return static_cast<_Derived*>(this)->_M_timedlock(__ts); } -#ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK +#if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK template<typename _Duration> bool _M_try_lock_until(const chrono::time_point<chrono::steady_clock, @@ -377,7 +377,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_timedlock(const __gthread_time_t& __ts) { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); } -#ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK +#if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK bool _M_clocklock(clockid_t __clockid, const __gthread_time_t& __ts) { return !pthread_mutex_clocklock(&_M_mutex, __clockid, &__ts); } @@ -733,7 +733,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } -#ifdef __cpp_lib_scoped_lock // C++ >= 17 && hosted && gthread +#ifdef __cpp_lib_scoped_lock // C++ >= 17 /** @brief A scoped lock type for multiple lockable objects. * * A scoped_lock controls mutex ownership within a scope, releasing diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric index 490963e..cbabf031 100644 --- a/libstdc++-v3/include/std/numeric +++ b/libstdc++-v3/include/std/numeric @@ -582,7 +582,7 @@ namespace __detail { if (__first != __last) { - auto __init = *__first; + auto __init = std::move(*__first); *__result++ = __init; ++__first; if (__first != __last) @@ -645,8 +645,8 @@ namespace __detail { while (__first != __last) { - auto __v = __init; - __init = __binary_op(__init, __unary_op(*__first)); + auto __v = std::move(__init); + __init = __binary_op(__v, __unary_op(*__first)); ++__first; *__result++ = std::move(__v); } diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index a616dc0..e5051d7 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -36,6 +36,7 @@ #define __glibcxx_want_freestanding_optional #define __glibcxx_want_optional +#define __glibcxx_want_optional_range_support #define __glibcxx_want_constrained_equality #include <bits/version.h> @@ -57,6 +58,11 @@ #if __cplusplus > 202002L # include <concepts> #endif +#ifdef __cpp_lib_optional_range_support // C++ >= 26 +# include <bits/formatfwd.h> +# include <bits/ranges_base.h> +# include <bits/stl_iterator.h> +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -858,6 +864,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: using value_type = _Tp; +#ifdef __cpp_lib_optional_range_support // >= C++26 + using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional>; + using const_iterator = __gnu_cxx::__normal_iterator<const _Tp*, optional>; +#endif constexpr optional() noexcept { } @@ -1158,6 +1168,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } +#ifdef __cpp_lib_optional_range_support // >= C++26 + // Iterator support. + constexpr iterator begin() noexcept + { + return iterator( + this->_M_is_engaged() ? std::addressof(this->_M_get()) : nullptr + ); + } + + constexpr const_iterator begin() const noexcept + { + return const_iterator( + this->_M_is_engaged() ? std::addressof(this->_M_get()) : nullptr + ); + } + + constexpr iterator end() noexcept + { + return begin() + has_value(); + } + + constexpr const_iterator end() const noexcept + { + return begin() + has_value(); + } +#endif // __cpp_lib_optional_range_support + // Observers. constexpr const _Tp* operator->() const noexcept @@ -1703,6 +1740,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(noexcept(__lhs.swap(__rhs))) { __lhs.swap(__rhs); } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2766. Swapping non-swappable types template<typename _Tp> enable_if_t<!(is_move_constructible_v<_Tp> && is_swappable_v<_Tp>)> swap(optional<_Tp>&, optional<_Tp>&) = delete; @@ -1772,6 +1811,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Tp> optional(_Tp) -> optional<_Tp>; #endif +#ifdef __cpp_lib_optional_range_support // >= C++26 + template<typename _Tp> + inline constexpr bool + ranges::enable_view<optional<_Tp>> = true; + + template<typename _Tp> + inline constexpr range_format + format_kind<optional<_Tp>> = range_format::disabled; +#endif // __cpp_lib_optional_range_support + #undef _GLIBCXX_USE_CONSTRAINTS_FOR_OPTIONAL _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream index 644e568..3a0a0d3 100644 --- a/libstdc++-v3/include/std/ostream +++ b/libstdc++-v3/include/std/ostream @@ -193,7 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __format::_Str_sink<char> __buf; std::vformat_to(__buf.out(), __os.getloc(), __fmt, __args); - auto __out = __buf.view(); + auto __out = __buf._M_span(); void* __open_terminal(streambuf*); error_code __write_to_terminal(void*, span<char>); diff --git a/libstdc++-v3/include/std/print b/libstdc++-v3/include/std/print index ea1aaac..92dbe11 100644 --- a/libstdc++-v3/include/std/print +++ b/libstdc++-v3/include/std/print @@ -73,7 +73,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #else __format::_Str_sink<char> __buf; std::vformat_to(__buf.out(), __fmt, __args); - auto __out = __buf.view(); + auto __out = __buf._M_span(); void* __open_terminal(FILE*); error_code __write_to_terminal(void*, span<char>); diff --git a/libstdc++-v3/include/std/queue b/libstdc++-v3/include/std/queue index 74b6c07..1b76088 100644 --- a/libstdc++-v3/include/std/queue +++ b/libstdc++-v3/include/std/queue @@ -61,14 +61,94 @@ #include <bits/requires_hosted.h> // containers +#define __glibcxx_want_adaptor_iterator_pair_constructor +#define __glibcxx_want_containers_ranges +#include <bits/version.h> + #include <deque> #include <vector> #include <bits/stl_heap.h> #include <bits/stl_function.h> #include <bits/stl_queue.h> -#define __glibcxx_want_adaptor_iterator_pair_constructor -#define __glibcxx_want_containers_ranges -#include <bits/version.h> +#ifdef __glibcxx_format_ranges // C++ >= 23 && HOSTED +#include <bits/formatfwd.h> + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + // Standard does not constrain accepted _CharT, we do so we can + // befriend specializations. + template<__format::__char _CharT, typename _Tp, + formattable<_CharT> _Container> + struct formatter<queue<_Tp, _Container>, _CharT> + { + private: + using __maybe_const_adaptor + = __conditional_t< + __format::__const_formattable_range<_Container, _CharT>, + const queue<_Tp, _Container>, queue<_Tp, _Container>>; + + public: + // Standard declares this as template accepting unconstrained + // ParseContext type. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + // Standard declares this as template accepting unconstrained + // FormatContext type. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__maybe_const_adaptor& __a, + basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format(__a.c, __fc); } + + private: + // Standard uses formatter<ref_view<_Container>, _CharT>, but range_formatter + // provides same behavior. + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3881. Incorrect formatting of container adapters backed by std::string + range_formatter<_Tp, _CharT> _M_f; + }; + + template<__format::__char _CharT, typename _Tp, + formattable<_CharT> _Container, typename _Compare> + struct formatter<priority_queue<_Tp, _Container, _Compare>, _CharT> + { + private: + using __maybe_const_adaptor + = __conditional_t< + __format::__const_formattable_range<_Container, _CharT>, + const priority_queue<_Tp, _Container, _Compare>, + priority_queue<_Tp, _Container, _Compare>>; + + public: + // Standard declares this as template accepting unconstrained + // ParseContext type. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + // Standard declares this as template accepting unconstrained + // FormatContext type. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__maybe_const_adaptor& __a, + basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format(__a.c, __fc); } + + private: + // Standard uses formatter<ref_view<_Container>, _CharT>, but range_formatter + // provides same behavior. + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3881. Incorrect formatting of container adapters backed by std::string + range_formatter<_Tp, _CharT> _M_f; + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // __glibcxx_format_ranges + #endif /* _GLIBCXX_QUEUE */ diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 9300c36..f493da5 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -51,6 +51,7 @@ #include <utility> #include <variant> #endif +#include <bits/binders.h> #include <bits/ranges_util.h> #include <bits/refwrap.h> @@ -660,7 +661,7 @@ namespace ranges : _M_value(__value) { } - constexpr + constexpr explicit iota_view(type_identity_t<_Winc> __value, type_identity_t<_Bound> __bound) : _M_value(__value), _M_bound(__bound) @@ -669,19 +670,19 @@ namespace ranges __glibcxx_assert( bool(__value <= __bound) ); } - constexpr + constexpr explicit iota_view(_Iterator __first, _Iterator __last) requires same_as<_Winc, _Bound> : iota_view(__first._M_value, __last._M_value) { } - constexpr + constexpr explicit iota_view(_Iterator __first, unreachable_sentinel_t __last) requires same_as<_Bound, unreachable_sentinel_t> : iota_view(__first._M_value, __last) { } - constexpr + constexpr explicit iota_view(_Iterator __first, _Sentinel __last) requires (!same_as<_Winc, _Bound>) && (!same_as<_Bound, unreachable_sentinel_t>) : iota_view(__first._M_value, __last._M_bound) @@ -1047,14 +1048,15 @@ namespace views::__adaptor template<typename _Adaptor, typename... _Args> struct _Partial : _RangeAdaptorClosure<_Partial<_Adaptor, _Args...>> { - tuple<_Args...> _M_args; + using _Binder = _Bind_back_t<_Adaptor, _Args...>; + [[no_unique_address]] _Binder _M_binder; // First parameter is to ensure this constructor is never used // instead of the copy/move constructor. template<typename... _Ts> constexpr _Partial(int, _Ts&&... __args) - : _M_args(std::forward<_Ts>(__args)...) + : _M_binder(0, _Adaptor(), std::forward<_Ts>(__args)...) { } // Invoke _Adaptor with arguments __r, _M_args... according to the @@ -1065,75 +1067,21 @@ namespace views::__adaptor constexpr auto operator()(this _Self&& __self, _Range&& __r) { - auto __forwarder = [&__r] (auto&&... __args) { - return _Adaptor{}(std::forward<_Range>(__r), - std::forward<decltype(__args)>(__args)...); - }; - return std::apply(__forwarder, __like_t<_Self, _Partial>(__self)._M_args); + return _Binder::_S_call(__like_t<_Self, _Partial>(__self)._M_binder, + std::forward<_Range>(__r)); } #else template<typename _Range> requires __adaptor_invocable<_Adaptor, _Range, const _Args&...> constexpr auto operator()(_Range&& __r) const & - { - auto __forwarder = [&__r] (const auto&... __args) { - return _Adaptor{}(std::forward<_Range>(__r), __args...); - }; - return std::apply(__forwarder, _M_args); - } + { return _Binder::_S_call(_M_binder, std::forward<_Range>(__r)); } template<typename _Range> requires __adaptor_invocable<_Adaptor, _Range, _Args...> constexpr auto operator()(_Range&& __r) && - { - auto __forwarder = [&__r] (auto&... __args) { - return _Adaptor{}(std::forward<_Range>(__r), std::move(__args)...); - }; - return std::apply(__forwarder, _M_args); - } - - template<typename _Range> - constexpr auto - operator()(_Range&& __r) const && = delete; -#endif - }; - - // A lightweight specialization of the above primary template for - // the common case where _Adaptor accepts a single extra argument. - template<typename _Adaptor, typename _Arg> - struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure<_Partial<_Adaptor, _Arg>> - { - _Arg _M_arg; - - template<typename _Tp> - constexpr - _Partial(int, _Tp&& __arg) - : _M_arg(std::forward<_Tp>(__arg)) - { } - -#if __cpp_explicit_this_parameter - template<typename _Self, typename _Range> - requires __adaptor_invocable<_Adaptor, _Range, __like_t<_Self, _Arg>> - constexpr auto - operator()(this _Self&& __self, _Range&& __r) - { - return _Adaptor{}(std::forward<_Range>(__r), - __like_t<_Self, _Partial>(__self)._M_arg); - } -#else - template<typename _Range> - requires __adaptor_invocable<_Adaptor, _Range, const _Arg&> - constexpr auto - operator()(_Range&& __r) const & - { return _Adaptor{}(std::forward<_Range>(__r), _M_arg); } - - template<typename _Range> - requires __adaptor_invocable<_Adaptor, _Range, _Arg> - constexpr auto - operator()(_Range&& __r) && - { return _Adaptor{}(std::forward<_Range>(__r), std::move(_M_arg)); } + { return _Binder::_S_call(std::move(_M_binder), std::forward<_Range>(__r)); } template<typename _Range> constexpr auto @@ -1150,12 +1098,13 @@ namespace views::__adaptor && (is_trivially_copy_constructible_v<_Args> && ...) struct _Partial<_Adaptor, _Args...> : _RangeAdaptorClosure<_Partial<_Adaptor, _Args...>> { - tuple<_Args...> _M_args; + using _Binder = _Bind_back_t<_Adaptor, _Args...>; + [[no_unique_address]] _Binder _M_binder; template<typename... _Ts> constexpr _Partial(int, _Ts&&... __args) - : _M_args(std::forward<_Ts>(__args)...) + : _M_binder(0, _Adaptor(), std::forward<_Ts>(__args)...) { } // Invoke _Adaptor with arguments __r, const _M_args&... regardless @@ -1164,36 +1113,7 @@ namespace views::__adaptor requires __adaptor_invocable<_Adaptor, _Range, const _Args&...> constexpr auto operator()(_Range&& __r) const - { - auto __forwarder = [&__r] (const auto&... __args) { - return _Adaptor{}(std::forward<_Range>(__r), __args...); - }; - return std::apply(__forwarder, _M_args); - } - - static constexpr bool _S_has_simple_call_op = true; - }; - - // A lightweight specialization of the above template for the common case - // where _Adaptor accepts a single extra argument. - template<typename _Adaptor, typename _Arg> - requires __adaptor_has_simple_extra_args<_Adaptor, _Arg> - && is_trivially_copy_constructible_v<_Arg> - struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure<_Partial<_Adaptor, _Arg>> - { - _Arg _M_arg; - - template<typename _Tp> - constexpr - _Partial(int, _Tp&& __arg) - : _M_arg(std::forward<_Tp>(__arg)) - { } - - template<typename _Range> - requires __adaptor_invocable<_Adaptor, _Range, const _Arg&> - constexpr auto - operator()(_Range&& __r) const - { return _Adaptor{}(std::forward<_Range>(__r), _M_arg); } + { return _Binder::_S_call(_M_binder, std::forward<_Range>(__r)); } static constexpr bool _S_has_simple_call_op = true; }; @@ -1585,8 +1505,6 @@ namespace views::__adaptor }; template<random_access_range _Range> - requires (sizeof(range_difference_t<_Range>) - <= sizeof(iterator_t<_Range>)) struct _CachedPosition<_Range> { private: @@ -1811,7 +1729,7 @@ namespace views::__adaptor && default_initializable<_Pred>) = default; - constexpr + constexpr explicit filter_view(_Vp __base, _Pred __pred) : _M_base(std::move(__base)), _M_pred(std::move(__pred)) { } @@ -2188,7 +2106,7 @@ namespace views::__adaptor && default_initializable<_Fp>) = default; - constexpr + constexpr explicit transform_view(_Vp __base, _Fp __fun) : _M_base(std::move(__base)), _M_fun(std::move(__fun)) { } @@ -2323,7 +2241,7 @@ namespace views::__adaptor public: take_view() requires default_initializable<_Vp> = default; - constexpr + constexpr explicit take_view(_Vp __base, range_difference_t<_Vp> __count) : _M_base(std::move(__base)), _M_count(std::move(__count)) { } @@ -2562,7 +2480,7 @@ namespace views::__adaptor && default_initializable<_Pred>) = default; - constexpr + constexpr explicit take_while_view(_Vp __base, _Pred __pred) : _M_base(std::move(__base)), _M_pred(std::move(__pred)) { } @@ -2650,7 +2568,7 @@ namespace views::__adaptor public: drop_view() requires default_initializable<_Vp> = default; - constexpr + constexpr explicit drop_view(_Vp __base, range_difference_t<_Vp> __count) : _M_base(std::move(__base)), _M_count(__count) { __glibcxx_assert(__count >= 0); } @@ -2804,7 +2722,7 @@ namespace views::__adaptor && default_initializable<_Pred>) = default; - constexpr + constexpr explicit drop_while_view(_Vp __base, _Pred __pred) : _M_base(std::move(__base)), _M_pred(std::move(__pred)) { } @@ -2971,7 +2889,12 @@ namespace views::__adaptor } if constexpr (_S_ref_is_glvalue) - _M_inner.reset(); + { + if constexpr (forward_iterator<_Inner_iter>) + _M_inner = _Inner_iter(); + else + _M_inner.reset(); + } } static constexpr auto @@ -3011,6 +2934,24 @@ namespace views::__adaptor return *_M_parent->_M_outer; } + constexpr _Inner_iter& + _M_get_inner() noexcept + { + if constexpr (forward_iterator<_Inner_iter>) + return _M_inner; + else + return *_M_inner; + } + + constexpr const _Inner_iter& + _M_get_inner() const noexcept + { + if constexpr (forward_iterator<_Inner_iter>) + return _M_inner; + else + return *_M_inner; + } + constexpr _Iterator(_Parent* __parent, _Outer_iter __outer) requires forward_range<_Base> : _M_outer(std::move(__outer)), _M_parent(__parent) @@ -3022,8 +2963,11 @@ namespace views::__adaptor { _M_satisfy(); } [[no_unique_address]] - __detail::__maybe_present_t<forward_range<_Base>, _Outer_iter> _M_outer; - optional<_Inner_iter> _M_inner; + __detail::__maybe_present_t<forward_range<_Base>, _Outer_iter> _M_outer + = decltype(_M_outer)(); + __conditional_t<forward_iterator<_Inner_iter>, + _Inner_iter, optional<_Inner_iter>> _M_inner + = decltype(_M_inner)(); _Parent* _M_parent = nullptr; public: @@ -3047,7 +2991,7 @@ namespace views::__adaptor constexpr decltype(auto) operator*() const - { return **_M_inner; } + { return *_M_get_inner(); } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3500. join_view::iterator::operator->() is bogus @@ -3055,7 +2999,7 @@ namespace views::__adaptor operator->() const requires __detail::__has_arrow<_Inner_iter> && copyable<_Inner_iter> - { return *_M_inner; } + { return _M_get_inner(); } constexpr _Iterator& operator++() @@ -3066,7 +3010,7 @@ namespace views::__adaptor else return *_M_parent->_M_inner; }(); - if (++*_M_inner == ranges::end(__inner_range)) + if (++_M_get_inner() == ranges::end(__inner_range)) { ++_M_get_outer(); _M_satisfy(); @@ -3096,9 +3040,9 @@ namespace views::__adaptor { if (_M_outer == ranges::end(_M_parent->_M_base)) _M_inner = ranges::end(__detail::__as_lvalue(*--_M_outer)); - while (*_M_inner == ranges::begin(__detail::__as_lvalue(*_M_outer))) - *_M_inner = ranges::end(__detail::__as_lvalue(*--_M_outer)); - --*_M_inner; + while (_M_get_inner() == ranges::begin(__detail::__as_lvalue(*_M_outer))) + _M_get_inner() = ranges::end(__detail::__as_lvalue(*--_M_outer)); + --_M_get_inner(); return *this; } @@ -3125,14 +3069,14 @@ namespace views::__adaptor friend constexpr decltype(auto) iter_move(const _Iterator& __i) - noexcept(noexcept(ranges::iter_move(*__i._M_inner))) - { return ranges::iter_move(*__i._M_inner); } + noexcept(noexcept(ranges::iter_move(__i._M_get_inner()))) + { return ranges::iter_move(__i._M_get_inner()); } friend constexpr void iter_swap(const _Iterator& __x, const _Iterator& __y) - noexcept(noexcept(ranges::iter_swap(*__x._M_inner, *__y._M_inner))) + noexcept(noexcept(ranges::iter_swap(__x._M_get_inner(), __y._M_get_inner()))) requires indirectly_swappable<_Inner_iter> - { return ranges::iter_swap(*__x._M_inner, *__y._M_inner); } + { return ranges::iter_swap(__x._M_get_inner(), __y._M_get_inner()); } friend _Iterator<!_Const>; template<bool> friend struct _Sentinel; @@ -3376,7 +3320,8 @@ namespace views::__adaptor [[no_unique_address]] __detail::__maybe_present_t<forward_range<_Vp>, - iterator_t<_Base>> _M_current; + iterator_t<_Base>> _M_current + = decltype(_M_current)(); bool _M_trailing_empty = false; public: @@ -3641,7 +3586,7 @@ namespace views::__adaptor && default_initializable<_Pattern>) = default; - constexpr + constexpr explicit lazy_split_view(_Vp __base, _Pattern __pattern) : _M_base(std::move(__base)), _M_pattern(std::move(__pattern)) { } @@ -3649,7 +3594,7 @@ namespace views::__adaptor template<input_range _Range> requires constructible_from<_Vp, views::all_t<_Range>> && constructible_from<_Pattern, single_view<range_value_t<_Range>>> - constexpr + constexpr explicit lazy_split_view(_Range&& __r, range_value_t<_Range> __e) : _M_base(views::all(std::forward<_Range>(__r))), _M_pattern(views::single(std::move(__e))) @@ -3766,7 +3711,7 @@ namespace views::__adaptor && default_initializable<_Pattern>) = default; - constexpr + constexpr explicit split_view(_Vp __base, _Pattern __pattern) : _M_base(std::move(__base)), _M_pattern(std::move(__pattern)) { } @@ -3774,7 +3719,7 @@ namespace views::__adaptor template<forward_range _Range> requires constructible_from<_Vp, views::all_t<_Range>> && constructible_from<_Pattern, single_view<range_value_t<_Range>>> - constexpr + constexpr explicit split_view(_Range&& __r, range_value_t<_Range> __e) : _M_base(views::all(std::forward<_Range>(__r))), _M_pattern(views::single(std::move(__e))) @@ -5336,7 +5281,7 @@ namespace views::__adaptor requires move_constructible<decay_t<_Fp>> && regular_invocable<decay_t<_Fp>&> && is_object_v<decay_t<invoke_result_t<decay_t<_Fp>&>>> constexpr auto - operator() [[nodiscard]] (_Fp&& __f) const + operator() [[nodiscard]] (_Fp&&) const { return views::empty<decay_t<invoke_result_t<decay_t<_Fp>&>>>; } @@ -6598,7 +6543,7 @@ namespace views::__adaptor } friend constexpr difference_type - operator-(default_sentinel_t __y, const _Iterator& __x) + operator-(default_sentinel_t, const _Iterator& __x) requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>> { return __detail::__div_ceil(__x._M_end - __x._M_current, __x._M_n); } @@ -7287,15 +7232,15 @@ namespace views::__adaptor using iterator_category = decltype(_S_iter_cat()); }; - template<bool> struct _Iterator; - template<bool> struct _Sentinel; + template<bool> class _Iterator; + template<bool> class _Sentinel; public: join_with_view() requires (default_initializable<_Vp> && default_initializable<_Pattern>) = default; - constexpr + constexpr explicit join_with_view(_Vp __base, _Pattern __pattern) : _M_base(std::move(__base)), _M_pattern(std::move(__pattern)) { } @@ -7303,7 +7248,7 @@ namespace views::__adaptor template<input_range _Range> requires constructible_from<_Vp, views::all_t<_Range>> && constructible_from<_Pattern, single_view<range_value_t<_InnerRange>>> - constexpr + constexpr explicit join_with_view(_Range&& __r, range_value_t<_InnerRange> __e) : _M_base(views::all(std::forward<_Range>(__r))), _M_pattern(views::single(std::move(__e))) @@ -7400,7 +7345,8 @@ namespace views::__adaptor _Parent* _M_parent = nullptr; [[no_unique_address]] - __detail::__maybe_present_t<forward_range<_Base>, _OuterIter> _M_outer_it; + __detail::__maybe_present_t<forward_range<_Base>, _OuterIter> _M_outer_it + = decltype(_M_outer_it)(); variant<_PatternIter, _InnerIter> _M_inner_it; constexpr _OuterIter& @@ -7743,7 +7689,7 @@ namespace views::__adaptor __detail::__box<_Tp> _M_value; [[no_unique_address]] _Bound _M_bound = _Bound(); - struct _Iterator; + class _Iterator; template<typename _Range> friend constexpr auto @@ -8303,7 +8249,7 @@ namespace views::__adaptor } friend constexpr difference_type - operator-(default_sentinel_t __y, const _Iterator& __x) + operator-(default_sentinel_t, const _Iterator& __x) requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>> { return __detail::__div_ceil(__x._M_end - __x._M_current, __x._M_stride); } @@ -9735,7 +9681,7 @@ namespace ranges end() requires (!(__detail::__simple_view<_Vs> && ...)) { constexpr auto __n = sizeof...(_Vs); - if constexpr ((semiregular<iterator_t<_Vs>> && ...) + if constexpr (__detail::__all_forward<false, _Vs...> && common_range<_Vs...[__n - 1]>) return _Iterator<false>(this, in_place_index<__n - 1>, ranges::end(std::get<__n - 1>(_M_views))); @@ -9747,7 +9693,7 @@ namespace ranges end() const requires (range<const _Vs> && ...) && __detail::__concatable<const _Vs...> { constexpr auto __n = sizeof...(_Vs); - if constexpr ((semiregular<iterator_t<const _Vs>> && ...) + if constexpr (__detail::__all_forward<true, _Vs...> && common_range<const _Vs...[__n - 1]>) return _Iterator<true>(this, in_place_index<__n - 1>, ranges::end(std::get<__n - 1>(_M_views))); diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore index bec5ac3..18d0407 100644 --- a/libstdc++-v3/include/std/semaphore +++ b/libstdc++-v3/include/std/semaphore @@ -35,29 +35,28 @@ #include <bits/requires_hosted.h> // concurrency -#if __cplusplus > 201703L -#include <bits/semaphore_base.h> - #define __glibcxx_want_semaphore #include <bits/version.h> -#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && (atomic_wait || posix_sem) +#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && atomic_wait +#include <bits/semaphore_base.h> + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - template<ptrdiff_t __least_max_value = __semaphore_impl::_S_max> + template<ptrdiff_t __least_max_value = _Semaphore_impl<2>::_S_max> class counting_semaphore { static_assert(__least_max_value >= 0); - static_assert(__least_max_value <= __semaphore_impl::_S_max); - __semaphore_impl _M_sem; + _Semaphore_impl<__least_max_value> _M_sem; public: - explicit counting_semaphore(ptrdiff_t __desired) noexcept - : _M_sem(__desired) - { } + constexpr explicit + counting_semaphore(ptrdiff_t __desired) noexcept + : _M_sem(__desired) + { __glibcxx_assert(__desired >= 0 && __desired <= max()); } ~counting_semaphore() = default; @@ -69,8 +68,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __least_max_value; } void - release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1))) - { _M_sem._M_release(__update); } + release(ptrdiff_t __update = 1) noexcept + { + [[maybe_unused]] ptrdiff_t __old = _M_sem._M_release(__update); + __glibcxx_assert(__update >= 0 && __update <= max() - __old); + } void acquire() noexcept(noexcept(_M_sem._M_acquire())) @@ -91,10 +93,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return _M_sem._M_try_acquire_until(__atime); } }; + /** @brief A binary semaphore + * + * @since C++20 + */ using binary_semaphore = std::counting_semaphore<1>; _GLIBCXX_END_NAMESPACE_VERSION } // namespace -#endif // cpp_lib_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE #endif // __cpp_lib_semaphore #endif // _GLIBCXX_SEMAPHORE diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 49ab910..5808911 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -376,7 +376,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else static_assert(_Count <= extent); using _Sp = span<element_type, _Count>; - return _Sp{ _SizedPtr{this->data()} }; + return _Sp(_SizedPtr{this->data()}); } [[nodiscard]] @@ -384,7 +384,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION first(size_type __count) const noexcept { __glibcxx_assert(__count <= size()); - return { this->data(), __count }; + return span<element_type>(this->data(), __count); } template<size_t _Count> @@ -397,7 +397,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else static_assert(_Count <= extent); using _Sp = span<element_type, _Count>; - return _Sp{ _SizedPtr{this->data() + (this->size() - _Count)} }; + return _Sp(_SizedPtr{this->data() + (this->size() - _Count)}); } [[nodiscard]] @@ -405,7 +405,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION last(size_type __count) const noexcept { __glibcxx_assert(__count <= size()); - return { this->data() + (this->size() - __count), __count }; + return span<element_type>(this->data() + (this->size() - __count), + __count); } template<size_t _Offset, size_t _Count = dynamic_extent> @@ -424,7 +425,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Sp = span<element_type, _S_subspan_extent<_Offset, _Count>()>; if constexpr (_Count == dynamic_extent) - return _Sp{ this->data() + _Offset, this->size() - _Offset }; + return _Sp(this->data() + _Offset, this->size() - _Offset); else { if constexpr (_Extent == dynamic_extent) @@ -437,7 +438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(_Count <= extent); static_assert(_Count <= (extent - _Offset)); } - return _Sp{ _SizedPtr{this->data() + _Offset} }; + return _Sp(_SizedPtr{this->data() + _Offset}); } } @@ -454,7 +455,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __glibcxx_assert(__count <= size()); __glibcxx_assert(__offset + __count <= size()); } - return {this->data() + __offset, __count}; + return span<element_type>(this->data() + __offset, __count); } private: @@ -476,6 +477,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; // deduction guides + namespace __detail + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4351. integral-constant-like needs more remove_cvref_t + template<typename _Tp> + concept __integral_constant_like = + is_integral_v<remove_cvref_t<decltype(_Tp::value)>> + && !is_same_v<bool, remove_cvref_t<decltype(_Tp::value)>> + && convertible_to<_Tp, decltype(_Tp::value)> + && equality_comparable_with<_Tp, decltype(_Tp::value)> + && bool_constant<_Tp() == _Tp::value>::value + && bool_constant<static_cast<decltype(_Tp::value)>(_Tp()) == _Tp::value> + ::value; + + template<typename _Tp> + constexpr size_t __maybe_static_ext = dynamic_extent; + + template<__integral_constant_like _Tp> + constexpr size_t __maybe_static_ext<_Tp> = {_Tp::value}; + } template<typename _Type, size_t _ArrayExtent> span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>; @@ -489,7 +510,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<contiguous_iterator _Iter, typename _End> span(_Iter, _End) - -> span<remove_reference_t<iter_reference_t<_Iter>>>; + -> span<remove_reference_t<iter_reference_t<_Iter>>, + __detail::__maybe_static_ext<_End>>; template<ranges::contiguous_range _Range> span(_Range &&) diff --git a/libstdc++-v3/include/std/sstream b/libstdc++-v3/include/std/sstream index ad0c16a..b1b4126 100644 --- a/libstdc++-v3/include/std/sstream +++ b/libstdc++-v3/include/std/sstream @@ -41,8 +41,16 @@ #include <istream> #include <ostream> + #include <bits/alloc_traits.h> // allocator_traits, __allocator_like +#define __glibcxx_want_sstream_from_string_view +#include <bits/version.h> + +#ifdef __cpp_lib_sstream_from_string_view +# include <string_view> +#endif + #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI # define _GLIBCXX_LVAL_REF_QUAL & # define _GLIBCXX_SSTREAM_ALWAYS_INLINE @@ -52,8 +60,6 @@ # define _GLIBCXX_SSTREAM_ALWAYS_INLINE [[__gnu__::__always_inline__]] #endif - - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -159,6 +165,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer explicit basic_stringbuf(const allocator_type& __a) : basic_stringbuf(ios_base::in | std::ios_base::out, __a) @@ -197,7 +204,36 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 | ios_base::out) : basic_stringbuf(__s, __mode, allocator_type{}) { } +#endif +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + explicit + basic_stringbuf(const _Tp& __t, + ios_base::openmode __mode = ios_base::in | ios_base::out) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_stringbuf(__t, __mode, allocator_type{}) + { } + + template<typename _Tp> + basic_stringbuf(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_stringbuf(__t, ios_base::in | ios_base::out, __a) + { } + + template<typename _Tp> + basic_stringbuf(const _Tp& __t, ios_base::openmode __mode, + const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : _M_string(__t, __a) + { _M_stringbuf_init(__mode); } +#endif // C++26 + +#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a) : basic_stringbuf(std::move(__rhs), __a, __xfer_bufptrs(__rhs, this)) { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0); } @@ -262,6 +298,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -317,6 +354,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -335,6 +373,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } #endif +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + { + basic_string_view<_CharT, _Traits> __sv{__t}; + _M_string = __sv; + _M_stringbuf_init(_M_mode); + } +#endif // C++26 + protected: // Common initialization code goes here. void @@ -521,6 +572,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer + // The move constructor initializes an __xfer_bufptrs temporary then // delegates to this constructor to performs moves during its lifetime. basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a, @@ -584,7 +637,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ basic_istringstream() : __istream_type(), _M_stringbuf(ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an empty string buffer. @@ -601,7 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_istringstream(ios_base::openmode __mode) : __istream_type(), _M_stringbuf(__mode | ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an existing string buffer. @@ -620,7 +673,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_istringstream(const __string_type& __str, ios_base::openmode __mode = ios_base::in) : __istream_type(), _M_stringbuf(__str, __mode | ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief The destructor does nothing. @@ -637,9 +690,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_istringstream(basic_istringstream&& __rhs) : __istream_type(std::move(__rhs)), _M_stringbuf(std::move(__rhs._M_stringbuf)) - { __istream_type::set_rdbuf(&_M_stringbuf); } + { __istream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_istringstream(ios_base::openmode __mode, const allocator_type& __a) : __istream_type(), _M_stringbuf(__mode | ios_base::in, __a) { this->init(std::__addressof(_M_stringbuf)); } @@ -671,6 +725,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #endif // C++20 +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + explicit + basic_istringstream(const _Tp& __t, + ios_base::openmode __mode = ios_base::in) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_istringstream(__t, __mode, allocator_type{}) + { } + + template <typename _Tp> + basic_istringstream(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_istringstream(__t, ios_base::in, __a) + { } + + template <typename _Tp> + basic_istringstream(const _Tp& __t, ios_base::openmode __mode, + const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : __istream_type(), _M_stringbuf(__t, __mode | ios_base::in, __a) + { this->init(std::__addressof(_M_stringbuf)); } +#endif // C++26 + // 27.8.3.2 Assign and swap: basic_istringstream& @@ -702,7 +782,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NODISCARD __stringbuf_type* rdbuf() const - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } + { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } /** * @brief Copying out the string buffer. @@ -716,6 +796,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -747,6 +828,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -758,6 +840,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 str(__string_type&& __s) { _M_stringbuf.str(std::move(__s)); } #endif + +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + { _M_stringbuf.str(__t); } +#endif // C++26 }; @@ -812,7 +903,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ basic_ostringstream() : __ostream_type(), _M_stringbuf(ios_base::out) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an empty string buffer. @@ -829,7 +920,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_ostringstream(ios_base::openmode __mode) : __ostream_type(), _M_stringbuf(__mode | ios_base::out) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an existing string buffer. @@ -848,7 +939,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_ostringstream(const __string_type& __str, ios_base::openmode __mode = ios_base::out) : __ostream_type(), _M_stringbuf(__str, __mode | ios_base::out) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief The destructor does nothing. @@ -865,9 +956,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_ostringstream(basic_ostringstream&& __rhs) : __ostream_type(std::move(__rhs)), _M_stringbuf(std::move(__rhs._M_stringbuf)) - { __ostream_type::set_rdbuf(&_M_stringbuf); } + { __ostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_ostringstream(ios_base::openmode __mode, const allocator_type& __a) : __ostream_type(), _M_stringbuf(__mode | ios_base::out, __a) { this->init(std::__addressof(_M_stringbuf)); } @@ -899,6 +991,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #endif // C++20 +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + explicit + basic_ostringstream( + const _Tp& __t, ios_base::openmode __mode = ios_base::out) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_ostringstream(__t, __mode, allocator_type{}) + { } + + template <typename _Tp> + basic_ostringstream(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_ostringstream(__t, ios_base::out, __a) + { } + + template <typename _Tp> + basic_ostringstream(const _Tp& __t, ios_base::openmode __mode, + const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : __ostream_type(), _M_stringbuf(__t, __mode | ios_base::out, __a) + { this->init(std::__addressof(_M_stringbuf)); } +#endif // C++26 + // 27.8.3.2 Assign and swap: basic_ostringstream& @@ -930,7 +1048,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NODISCARD __stringbuf_type* rdbuf() const - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } + { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } /** * @brief Copying out the string buffer. @@ -944,6 +1062,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -975,6 +1094,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -986,6 +1106,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 str(__string_type&& __s) { _M_stringbuf.str(std::move(__s)); } #endif + +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + { _M_stringbuf.str(__t); } +#endif // C++26 }; @@ -1040,7 +1169,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ basic_stringstream() : __iostream_type(), _M_stringbuf(ios_base::out | ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an empty string buffer. @@ -1055,7 +1184,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_stringstream(ios_base::openmode __m) : __iostream_type(), _M_stringbuf(__m) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an existing string buffer. @@ -1072,7 +1201,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_stringstream(const __string_type& __str, ios_base::openmode __m = ios_base::out | ios_base::in) : __iostream_type(), _M_stringbuf(__str, __m) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief The destructor does nothing. @@ -1089,12 +1218,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_stringstream(basic_stringstream&& __rhs) : __iostream_type(std::move(__rhs)), _M_stringbuf(std::move(__rhs._M_stringbuf)) - { __iostream_type::set_rdbuf(&_M_stringbuf); } + { __iostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_stringstream(ios_base::openmode __mode, const allocator_type& __a) : __iostream_type(), _M_stringbuf(__mode, __a) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } explicit basic_stringstream(__string_type&& __str, @@ -1125,6 +1255,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #endif // C++20 +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + explicit + basic_stringstream(const _Tp& __t, + ios_base::openmode __mode = ios_base::in | ios_base::out) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_stringstream(__t, __mode, allocator_type{}) + { } + + template <typename _Tp> + basic_stringstream(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_stringstream(__t, ios_base::in | ios_base::out, __a) + { } + + template <typename _Tp> + basic_stringstream(const _Tp& __t, ios_base::openmode __mode, + const allocator_type& __a) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : __iostream_type(), _M_stringbuf(__t, __mode, __a) + { this->init(std::__addressof(_M_stringbuf)); } +#endif // C++26 + // 27.8.3.2 Assign and swap: basic_stringstream& @@ -1156,7 +1311,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NODISCARD __stringbuf_type* rdbuf() const - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } + { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } /** * @brief Copying out the string buffer. @@ -1170,6 +1325,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -1201,6 +1357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -1212,6 +1369,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 str(__string_type&& __s) { _M_stringbuf.str(std::move(__s)); } #endif + +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + { _M_stringbuf.str(__t); } +#endif // C++26 }; #if __cplusplus >= 201103L diff --git a/libstdc++-v3/include/std/stack b/libstdc++-v3/include/std/stack index 5cea476..a57a5a0 100644 --- a/libstdc++-v3/include/std/stack +++ b/libstdc++-v3/include/std/stack @@ -61,11 +61,53 @@ #include <bits/requires_hosted.h> // containers -#include <deque> -#include <bits/stl_stack.h> - #define __glibcxx_want_adaptor_iterator_pair_constructor #define __glibcxx_want_containers_ranges #include <bits/version.h> +#include <deque> +#include <bits/stl_stack.h> + +#ifdef __glibcxx_format_ranges // C++ >= 23 && HOSTED +#include <bits/formatfwd.h> + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + // Standard does not constrain accepted _CharT, we do so we can + // befriend specializations. + template<__format::__char _CharT, typename _Tp, + formattable<_CharT> _Container> + struct formatter<stack<_Tp, _Container>, _CharT> + { + private: + using __maybe_const_adaptor + = __conditional_t< + __format::__const_formattable_range<_Container, _CharT>, + const stack<_Tp, _Container>, stack<_Tp, _Container>>; + + public: + // Standard declares this as template accepting unconstrained + // ParseContext type. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + // Standard declares this as template accepting unconstrained + // FormatContext type. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__maybe_const_adaptor& __a, + basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format(__a.c, __fc); } + + private: + // Standard uses formatter<ref_view<_Container>, _CharT>. + range_formatter<_Tp, _CharT> _M_f; + }; +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // __glibcxx_format_ranges + + #endif /* _GLIBCXX_STACK */ diff --git a/libstdc++-v3/include/std/stop_token b/libstdc++-v3/include/std/stop_token index 1225b3a..b593daf 100644 --- a/libstdc++-v3/include/std/stop_token +++ b/libstdc++-v3/include/std/stop_token @@ -34,8 +34,7 @@ #define __glibcxx_want_jthread #include <bits/version.h> -#if __cplusplus > 201703L - +#ifdef __glibcxx_jthread // C++ >= 20 #include <atomic> #include <bits/std_thread.h> @@ -649,7 +648,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Callback> stop_callback(stop_token, _Callback) -> stop_callback<_Callback>; + /// @cond undocumented + namespace __detail::__variant + { + template<typename> struct _Never_valueless_alt; // see <variant> + + // Provide the strong exception-safety guarantee when emplacing a + // stop_token or stop_source into a variant. + template<> + struct _Never_valueless_alt<std::stop_token> + : true_type + { }; + + template<> + struct _Never_valueless_alt<std::stop_source> + : true_type + { }; + } // namespace __detail::__variant + /// @endcond + _GLIBCXX_END_NAMESPACE_VERSION -} // namespace -#endif // __cplusplus > 201703L +} // namespace std +#endif // __glibcxx_jthread #endif // _GLIBCXX_STOP_TOKEN diff --git a/libstdc++-v3/include/std/syncstream b/libstdc++-v3/include/std/syncstream index e2b5a19..1e17597 100644 --- a/libstdc++-v3/include/std/syncstream +++ b/libstdc++-v3/include/std/syncstream @@ -46,7 +46,6 @@ #include <bits/alloc_traits.h> #include <bits/allocator.h> #include <bits/functexcept.h> -#include <bits/functional_hash.h> #include <bits/std_mutex.h> namespace std _GLIBCXX_VISIBILITY(default) @@ -199,11 +198,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __mutex { #if _GLIBCXX_HAS_GTHREADS - mutex* _M_mtx; + mutex* _M_mtx = nullptr; - __mutex(void* __t) - : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr) - { } + __mutex(void* __t) // __t is the underlying sbuf, as hash seed. + { + extern mutex& __syncbuf_get_mutex(void*); // in src/c++20/syncbuf.cc + if (__t) _M_mtx = &__syncbuf_get_mutex(__t); + } void swap(__mutex& __other) noexcept @@ -220,17 +221,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { _M_mtx->unlock(); } - - // FIXME: This should be put in the .so - static mutex& - _S_get_mutex(void* __t) - { - const unsigned char __mask = 0xf; - static mutex __m[__mask + 1]; - - auto __key = _Hash_impl::hash(__t) & __mask; - return __m[__key]; - } #else __mutex(void*) { } void swap(__mutex&&) noexcept { } diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index d2f91ad..94ded714 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -294,10 +294,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION stop_source _M_stop_source; thread _M_thread; }; + + /// @cond undocumented + namespace __detail::__variant + { + template<typename> struct _Never_valueless_alt; // see <variant> + + // Provide the strong exception-safety guarantee when emplacing a + // jthread into a variant. + template<> + struct _Never_valueless_alt<std::jthread> + : true_type + { }; + } // namespace __detail::__variant + /// @endcond #endif // __cpp_lib_jthread #ifdef __cpp_lib_formatters // C++ >= 23 - template<typename _CharT> + // We deviate from the standard, that does not put requirements + // on _CharT here. + template<__format::__char _CharT> requires is_pointer_v<thread::native_handle_type> || is_integral_v<thread::native_handle_type> class formatter<thread::id, _CharT> @@ -307,6 +323,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION parse(basic_format_parse_context<_CharT>& __pc) { __format::_Spec<_CharT> __spec{}; + __spec._M_align = __format::_Align_right; const auto __last = __pc.end(); auto __first = __pc.begin(); @@ -334,36 +351,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__finished()) return __first; - __throw_format_error("format error: invalid format-spec for " - "std::thread::id"); + std::__throw_format_error("format error: invalid format-spec for " + "std::thread::id"); } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(thread::id __id, basic_format_context<_Out, _CharT>& __fc) const { - basic_string_view<_CharT> __sv; - if constexpr (is_same_v<_CharT, char>) - __sv = "{}thread::id of a non-executing thread"; - else - __sv = L"{}thread::id of a non-executing thread"; - basic_string<_CharT> __str; + if (__id == thread::id()) - __sv.remove_prefix(2); - else { - using _FmtStr = __format::_Runtime_format_string<_CharT>; - // Convert non-void pointers to const void* for formatted output. - using __output_type - = __conditional_t<is_pointer_v<thread::native_handle_type>, - const void*, - thread::native_handle_type>; - auto __o = static_cast<__output_type>(__id._M_thread); - __sv = __str = std::format(_FmtStr(__sv.substr(0, 2)), __o); + const _CharT* __msg; + if constexpr (is_same_v<_CharT, char>) + __msg = "thread::id of a non-executing thread"; + else + __msg = L"thread::id of a non-executing thread"; + + __format::__formatter_str<_CharT> __formatter(_M_spec); + return __formatter.format(__msg, __fc); } - return __format::__write_padded_as_spec(__sv, __sv.size(), - __fc, _M_spec, - __format::_Align_right); + + using _HandleFormatter + = __conditional_t<is_pointer_v<thread::native_handle_type>, + __format::__formatter_ptr<_CharT>, + __format::__formatter_int<_CharT>>; + + _HandleFormatter __formatter(_M_spec); + return __formatter.format(__id._M_thread, __fc); } private: diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 2e69af1..2e6499e 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -2835,6 +2835,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __x.swap(__y); } #if __cpp_lib_ranges_zip // >= C++23 + /// Exchange the values of two const tuples (if const elements can be swapped) template<typename... _Elements> requires (is_swappable_v<const _Elements> && ...) constexpr void @@ -2844,7 +2845,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // C++23 #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 - /// Exchange the values of two const tuples (if const elements can be swapped) + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2766. Swapping non-swappable types template<typename... _Elements> _GLIBCXX20_CONSTEXPR typename enable_if<!__and_<__is_swappable<_Elements>...>::value>::type @@ -2939,19 +2941,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif #ifdef __cpp_lib_make_from_tuple // C++ >= 17 + template <typename _Tp, typename _Tuple, typename _Seq + = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>> + constexpr bool __can_make_from_tuple = false; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3528. make_from_tuple can perform (the equivalent of) a C-style cast + template <typename _Tp, typename _Tuple, size_t... _Idx> + constexpr bool __can_make_from_tuple<_Tp, _Tuple, index_sequence<_Idx...>> + = is_constructible_v<_Tp, + decltype(std::get<_Idx>(std::declval<_Tuple>()))...>; + template <typename _Tp, typename _Tuple, size_t... _Idx> constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>) - { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); } + { + static_assert(__can_make_from_tuple<_Tp, _Tuple, index_sequence<_Idx...>>); + return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); + } #if __cpp_lib_tuple_like // >= C++23 template <typename _Tp, __tuple_like _Tuple> #else template <typename _Tp, typename _Tuple> #endif - constexpr _Tp + constexpr auto make_from_tuple(_Tuple&& __t) noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>) +#ifdef __cpp_concepts // >= C++20 + -> _Tp + requires __can_make_from_tuple<_Tp, _Tuple> +#else + -> __enable_if_t<__can_make_from_tuple<_Tp, _Tuple>, _Tp> +#endif { constexpr size_t __n = tuple_size_v<remove_reference_t<_Tuple>>; #if __has_builtin(__reference_constructs_from_temporary) diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 676cdf2..77ebb7e 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -41,6 +41,7 @@ #define __glibcxx_want_bool_constant #define __glibcxx_want_bounded_array_traits +#define __glibcxx_want_constant_wrapper #define __glibcxx_want_has_unique_object_representations #define __glibcxx_want_integral_constant_callable #define __glibcxx_want_is_aggregate @@ -280,11 +281,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Forward declarations template<typename> - struct is_reference; - template<typename> - struct is_function; - template<typename> - struct is_void; + struct is_object; template<typename> struct remove_cv; template<typename> @@ -294,21 +291,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename> struct __is_array_unknown_bounds; + // An object type which is not an unbounded array. + // It might still be an incomplete type, but if this is false_type + // then we can be certain it's not a complete object type. + template<typename _Tp> + using __maybe_complete_object_type + = __and_<is_object<_Tp>, __not_<__is_array_unknown_bounds<_Tp>>>; + // Helper functions that return false_type for incomplete classes, // incomplete unions and arrays of known bound from those. - template <typename _Tp, size_t = sizeof(_Tp)> - constexpr true_type __is_complete_or_unbounded(__type_identity<_Tp>) - { return {}; } - - template <typename _TypeIdentity, - typename _NestedType = typename _TypeIdentity::type> - constexpr typename __or_< - is_reference<_NestedType>, - is_function<_NestedType>, - is_void<_NestedType>, - __is_array_unknown_bounds<_NestedType> - >::type __is_complete_or_unbounded(_TypeIdentity) + // More specialized overload for complete object types (returning true_type). + template<typename _Tp, + typename = __enable_if_t<__maybe_complete_object_type<_Tp>::value>, + size_t = sizeof(_Tp)> + constexpr true_type + __is_complete_or_unbounded(__type_identity<_Tp>) + { return {}; }; + + // Less specialized overload for reference and unknown-bound array types + // (returning true_type), and incomplete types (returning false_type). + template<typename _TypeIdentity, + typename _NestedType = typename _TypeIdentity::type> + constexpr typename __not_<__maybe_complete_object_type<_NestedType>>::type + __is_complete_or_unbounded(_TypeIdentity) { return {}; } // __remove_cv_t (std::remove_cv_t for C++11). @@ -459,6 +465,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_3> : public true_type { }; #endif + +#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ + __extension__ + template<> + struct __is_integral_helper<__int128> + : public true_type { }; + + __extension__ + template<> + struct __is_integral_helper<unsigned __int128> + : public true_type { }; +#endif + /// @endcond /// is_integral @@ -514,7 +533,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public true_type { }; #endif -#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128) +#ifdef _GLIBCXX_USE_FLOAT128 template<> struct __is_floating_point_helper<__float128> : public true_type { }; @@ -1036,9 +1055,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_array_unknown_bounds<_Tp[]> : public true_type { }; + /// @endcond // Destructible and constructible type properties. +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible) + /// is_destructible + template<typename _Tp> + struct is_destructible + : public __bool_constant<__is_destructible(_Tp)> + { }; +#else + /// @cond undocumented + // In N3290 is_destructible does not say anything about function // types and abstract types, see LWG 2049. This implementation // describes function types as non-destructible and all complete @@ -1090,7 +1119,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; +#endif +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible) + /// is_nothrow_destructible + template<typename _Tp> + struct is_nothrow_destructible + : public __bool_constant<__is_nothrow_destructible(_Tp)> + { }; +#else /// @cond undocumented // is_nothrow_destructible requires that is_destructible is @@ -1144,6 +1181,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; +#endif /// @cond undocumented template<typename _Tp, typename... _Args> @@ -1451,6 +1489,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION "template argument must be a complete class or an unbounded array"); }; +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible) + /// is_trivially_destructible + template<typename _Tp> + struct is_trivially_destructible + : public __bool_constant<__is_trivially_destructible(_Tp)> + { }; +#else /// is_trivially_destructible template<typename _Tp> struct is_trivially_destructible @@ -1460,7 +1505,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; - +#endif /// has_virtual_destructor template<typename _Tp> @@ -1896,6 +1941,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __make_unsigned<__GLIBCXX_TYPE_INT_N_3> { using __type = unsigned __GLIBCXX_TYPE_INT_N_3; }; #endif +#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ + __extension__ + template<> + struct __make_unsigned<__int128> + { using __type = unsigned __int128; }; +#endif // Select between integral and enum: not possible to be both. template<typename _Tp, @@ -1942,8 +1993,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : __make_unsigned_selector_base { // With -fshort-enums, an enum may be as small as a char. + __extension__ using _UInts = _List<unsigned char, unsigned short, unsigned int, - unsigned long, unsigned long long>; + unsigned long, unsigned long long +#ifdef __SIZEOF_INT128__ + , unsigned __int128 +#endif + >; using __unsigned_type = typename __select<sizeof(_Tp), _UInts>::__type; @@ -2056,6 +2112,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __make_signed<unsigned __GLIBCXX_TYPE_INT_N_3> { using __type = __GLIBCXX_TYPE_INT_N_3; }; #endif +#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ + __extension__ + template<> + struct __make_signed<unsigned __int128> + { using __type = __int128; }; +#endif // Select between integral and enum: not possible to be both. template<typename _Tp, @@ -3212,7 +3274,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Fn, typename... _ArgTypes> struct __is_invocable +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable) + : __bool_constant<__is_invocable(_Fn, _ArgTypes...)> +#else : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type +#endif { }; template<typename _Fn, typename _Tp, typename... _Args> @@ -3263,8 +3329,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // __is_nothrow_invocable (std::is_nothrow_invocable for C++11) template<typename _Fn, typename... _Args> struct __is_nothrow_invocable +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable) + : __bool_constant<__is_nothrow_invocable(_Fn, _Args...)> +#else : __and_<__is_invocable<_Fn, _Args...>, __call_is_nothrow_<_Fn, _Args...>>::type +#endif { }; #pragma GCC diagnostic push @@ -3573,8 +3643,13 @@ template <typename _Tp> inline constexpr bool is_move_assignable_v = __is_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible) +template <typename _Tp> + inline constexpr bool is_destructible_v = __is_destructible(_Tp); +#else template <typename _Tp> inline constexpr bool is_destructible_v = is_destructible<_Tp>::value; +#endif template <typename _Tp, typename... _Args> inline constexpr bool is_trivially_constructible_v @@ -3601,7 +3676,11 @@ template <typename _Tp> = __is_trivially_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); -#if __cpp_concepts +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible) +template <typename _Tp> + inline constexpr bool is_trivially_destructible_v + = __is_trivially_destructible(_Tp); +#elif __cpp_concepts template <typename _Tp> inline constexpr bool is_trivially_destructible_v = false; @@ -3646,9 +3725,15 @@ template <typename _Tp> inline constexpr bool is_nothrow_move_assignable_v = __is_nothrow_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible) +template <typename _Tp> + inline constexpr bool is_nothrow_destructible_v + = __is_nothrow_destructible(_Tp); +#else template <typename _Tp> inline constexpr bool is_nothrow_destructible_v = is_nothrow_destructible<_Tp>::value; +#endif template <typename _Tp> inline constexpr bool has_virtual_destructor_v @@ -3704,10 +3789,19 @@ template <typename _From, typename _To> inline constexpr bool is_convertible_v = is_convertible<_From, _To>::value; #endif template<typename _Fn, typename... _Args> - inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value; + inline constexpr bool is_invocable_v +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable) + = __is_invocable(_Fn, _Args...); +#else + = is_invocable<_Fn, _Args...>::value; +#endif template<typename _Fn, typename... _Args> inline constexpr bool is_nothrow_invocable_v +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable) + = __is_nothrow_invocable(_Fn, _Args...); +#else = is_nothrow_invocable<_Fn, _Args...>::value; +#endif template<typename _Ret, typename _Fn, typename... _Args> inline constexpr bool is_invocable_r_v = is_invocable_r<_Ret, _Fn, _Args...>::value; @@ -4002,7 +4096,8 @@ template<typename _Ret, typename _Fn, typename... _Args> #ifdef __cpp_lib_is_constant_evaluated // C++ >= 20 && HAVE_IS_CONST_EVAL /// Returns true only when called during constant evaluation. /// @since C++20 - constexpr inline bool + [[__gnu__::__always_inline__]] + constexpr bool is_constant_evaluated() noexcept { #if __cpp_if_consteval >= 202106L @@ -4186,6 +4281,398 @@ template<typename _Ret, typename _Fn, typename... _Args> #endif // C++2a +#if __cplusplus >= 201103L + // Stores a tuple of indices. Used by tuple and pair, and by bind() to + // extract the elements in a tuple. + template<size_t... _Indexes> struct _Index_tuple { }; + + // Builds an _Index_tuple<0, 1, 2, ..., _Num-1>. + template<size_t _Num> + struct _Build_index_tuple + { +#if __has_builtin(__make_integer_seq) + template<typename, size_t... _Indices> + using _IdxTuple = _Index_tuple<_Indices...>; + + // Clang defines __make_integer_seq for this purpose. + using __type = __make_integer_seq<_IdxTuple, size_t, _Num>; +#else + // For GCC and other compilers, use __integer_pack instead. + using __type = _Index_tuple<__integer_pack(_Num)...>; +#endif + }; +#endif // C++11 + +#ifdef __cpp_lib_constant_wrapper // C++ >= 26 + template<typename _Tp> + struct _CwFixedValue + { + using __type = _Tp; + + constexpr + _CwFixedValue(__type __v) noexcept + : _M_data(__v) { } + + __type _M_data; + }; + + template<typename _Tp, size_t _Extent> + struct _CwFixedValue<_Tp[_Extent]> + { + using __type = _Tp[_Extent]; + + constexpr + _CwFixedValue(_Tp (&__arr)[_Extent]) noexcept + : _CwFixedValue(__arr, typename _Build_index_tuple<_Extent>::__type()) + { } + + template<size_t... _Indices> + constexpr + _CwFixedValue(_Tp (&__arr)[_Extent], _Index_tuple<_Indices...>) noexcept + : _M_data{__arr[_Indices]...} + { } + + _Tp _M_data[_Extent]; + }; + + template<typename _Tp, size_t _Extent> + _CwFixedValue(_Tp (&)[_Extent]) -> _CwFixedValue<_Tp[_Extent]>; + + template<_CwFixedValue _Xv, + typename = typename decltype(_CwFixedValue(_Xv))::__type> + struct constant_wrapper; + + template<typename _Tp> + concept _ConstExprParam = requires + { + typename constant_wrapper<_Tp::value>; + }; + + struct _CwOperators + { + template<_ConstExprParam _Tp> + friend constexpr auto + operator+(_Tp) noexcept -> constant_wrapper<(+_Tp::value)> + { return {}; } + + template<_ConstExprParam _Tp> + friend constexpr auto + operator-(_Tp) noexcept -> constant_wrapper<(-_Tp::value)> + { return {}; } + + template<_ConstExprParam _Tp> + friend constexpr auto + operator~(_Tp) noexcept -> constant_wrapper<(~_Tp::value)> + { return {}; } + + template<_ConstExprParam _Tp> + friend constexpr auto + operator!(_Tp) noexcept -> constant_wrapper<(!_Tp::value)> + { return {}; } + + template<_ConstExprParam _Tp> + friend constexpr auto + operator&(_Tp) noexcept -> constant_wrapper<(&_Tp::value)> + { return {}; } + + template<_ConstExprParam _Tp> + friend constexpr auto + operator*(_Tp) noexcept -> constant_wrapper<(*_Tp::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator+(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value + _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator-(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value - _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator*(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value * _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator/(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value / _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator%(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value % _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator<<(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value << _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator>>(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value >> _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator&(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value & _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator|(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value | _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator^(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value ^ _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + requires (!is_constructible_v<bool, decltype(_Left::value)> + || !is_constructible_v<bool, decltype(_Right::value)>) + friend constexpr auto + operator&&(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value && _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + requires (!is_constructible_v<bool, decltype(_Left::value)> + || !is_constructible_v<bool, decltype(_Right::value)>) + friend constexpr auto + operator||(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value || _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator<=>(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value <=> _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator<(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value < _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator<=(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value <= _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator==(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value == _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator!=(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value != _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator>(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value > _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator>=(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value >= _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator,(_Left, _Right) noexcept = delete; + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator->*(_Left, _Right) noexcept + -> constant_wrapper<_Left::value->*(_Right::value)> + { return {}; } + + template<_ConstExprParam _Tp, _ConstExprParam... _Args> + constexpr auto + operator()(this _Tp, _Args...) noexcept + requires + requires(_Args...) { constant_wrapper<_Tp::value(_Args::value...)>(); } + { return constant_wrapper<_Tp::value(_Args::value...)>{}; } + + template<_ConstExprParam _Tp, _ConstExprParam... _Args> + constexpr auto + operator[](this _Tp, _Args...) noexcept + -> constant_wrapper<(_Tp::value[_Args::value...])> + { return {}; } + + template<_ConstExprParam _Tp> + constexpr auto + operator++(this _Tp) noexcept + requires requires(_Tp::value_type __x) { ++__x; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return ++__x; }()>{}; + } + + template<_ConstExprParam _Tp> + constexpr auto + operator++(this _Tp, int) noexcept + requires requires(_Tp::value_type __x) { __x++; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x++; }()>{}; + } + + template<_ConstExprParam _Tp> + constexpr auto + operator--(this _Tp) noexcept + requires requires(_Tp::value_type __x) { --__x; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return --__x; }()>{}; + } + + template<_ConstExprParam _Tp> + constexpr auto + operator--(this _Tp, int) noexcept + requires requires(_Tp::value_type __x) { __x--; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x--; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator+=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x += _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x += _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator-=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x -= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x -= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator*=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x *= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x *= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator/=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x /= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x /= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator%=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x %= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x %= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator&=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x &= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x &= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator|=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x |= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x |= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator^=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x ^= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x ^= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator<<=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x <<= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x <<= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator>>=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x >>= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x >>= _Right::value; }()>{}; + } + }; + + template<_CwFixedValue _Xv, typename> + struct constant_wrapper : _CwOperators + { + static constexpr const auto& value = _Xv._M_data; + using type = constant_wrapper; + using value_type = typename decltype(_Xv)::__type; + + template<_ConstExprParam _Right> + constexpr auto + operator=(_Right) const noexcept + requires requires(value_type __x) { __x = _Right::value; } + { + return constant_wrapper< + [] { auto __x = value; return __x = _Right::value; }()>{}; + } + + constexpr + operator decltype(auto)() const noexcept + { return value; } + }; + + template<_CwFixedValue _Tp> + constexpr auto cw = constant_wrapper<_Tp>{}; +#endif + /// @} group metaprogramming _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility index 1c15c75..8a85ccf 100644 --- a/libstdc++-v3/include/std/utility +++ b/libstdc++-v3/include/std/utility @@ -201,7 +201,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #ifdef __cpp_lib_to_underlying // C++ >= 23 /// Convert an object of enumeration type to its underlying type. template<typename _Tp> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr underlying_type_t<_Tp> to_underlying(_Tp __value) noexcept { return static_cast<underlying_type_t<_Tp>>(__value); } diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index ec46ff1..2f44f97 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -1387,6 +1387,8 @@ namespace __detail::__variant noexcept(noexcept(__lhs.swap(__rhs))) { __lhs.swap(__rhs); } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2766. Swapping non-swappable types template<typename... _Types> enable_if_t<!((is_move_constructible_v<_Types> && ...) && (is_swappable_v<_Types> && ...))> diff --git a/libstdc++-v3/include/tr2/dynamic_bitset b/libstdc++-v3/include/tr2/dynamic_bitset index 2446f35..b308e72 100644 --- a/libstdc++-v3/include/tr2/dynamic_bitset +++ b/libstdc++-v3/include/tr2/dynamic_bitset @@ -99,7 +99,9 @@ namespace tr2 if (__val == 0) return; - if _GLIBCXX17_CONSTEXPR (sizeof(__val) == sizeof(block_type)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + if constexpr (sizeof(__val) == sizeof(block_type)) _M_w[0] = __val; else { @@ -111,6 +113,7 @@ namespace tr2 __val >>= _S_bits_per_block; } } +#pragma GCC diagnostic pop } void @@ -667,13 +670,16 @@ namespace tr2 operator=(dynamic_bitset&& __b) noexcept(std::is_nothrow_move_assignable<_Base>::value) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr static_cast<_Base&>(*this) = static_cast<_Base&&>(__b); _M_Nb = __b._M_Nb; - if _GLIBCXX17_CONSTEXPR (std::is_nothrow_move_assignable<_Base>::value) + if constexpr (std::is_nothrow_move_assignable<_Base>::value) __b._M_Nb = 0; else if (get_allocator() == __b.get_allocator()) __b._M_Nb = 0; return *this; +#pragma GCC diagnostic pop } /** |