diff options
Diffstat (limited to 'libstdc++-v3/include/std')
41 files changed, 3608 insertions, 748 deletions
diff --git a/libstdc++-v3/include/std/algorithm b/libstdc++-v3/include/std/algorithm index 321a5e2..1563cdf 100644 --- a/libstdc++-v3/include/std/algorithm +++ b/libstdc++-v3/include/std/algorithm @@ -74,6 +74,7 @@ #define __glibcxx_want_ranges_contains #define __glibcxx_want_ranges_find_last #define __glibcxx_want_ranges_fold +#define __glibcxx_want_ranges_starts_ends_with #define __glibcxx_want_robust_nonmodifying_seq_ops #define __glibcxx_want_sample #define __glibcxx_want_shift diff --git a/libstdc++-v3/include/std/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..8b5d270 100644 --- a/libstdc++-v3/include/std/bitset +++ b/libstdc++-v3/include/std/bitset @@ -1605,6 +1605,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 +1615,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 +1676,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 +1687,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..dda49ce 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++ = '-'; @@ -452,7 +453,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 +563,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 +596,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 +606,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..cb8213e 100644 --- a/libstdc++-v3/include/std/chrono +++ b/libstdc++-v3/include/std/chrono @@ -2305,8 +2305,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __r *= 10; return __r; } - - template<typename _Duration> struct __utc_leap_second; } /// @endcond @@ -2481,30 +2479,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __byte_duration<ratio<1>> _M_s{}; bool _M_is_neg{}; __subseconds<precision> _M_ss{}; - - template<typename> friend struct __detail::__utc_leap_second; }; - /// @cond undocumented - namespace __detail - { - // Represents a time that is within a leap second insertion. - template<typename _Duration> - struct __utc_leap_second - { - explicit - __utc_leap_second(const sys_time<_Duration>& __s) - : _M_date(chrono::floor<days>(__s)), _M_time(__s - _M_date) - { - ++_M_time._M_s; - } - - sys_days _M_date; - hh_mm_ss<common_type_t<_Duration, days>> _M_time; - }; - } - /// @endcond - // 12/24 HOURS FUNCTIONS constexpr bool diff --git a/libstdc++-v3/include/std/complex b/libstdc++-v3/include/std/complex index 59ef905..d9d2d8a 100644 --- a/libstdc++-v3/include/std/complex +++ b/libstdc++-v3/include/std/complex @@ -969,7 +969,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif - // 26.2.7/4: arg(__z): Returns the phase angle of __z. + // C++11 26.4.7 [complex.value.ops]/4: arg(z): Returns the phase angle of z. template<typename _Tp> inline _Tp __complex_arg(const complex<_Tp>& __z) @@ -2123,8 +2123,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> std::complex<_Tp> acosh(const std::complex<_Tp>&); template<typename _Tp> std::complex<_Tp> asinh(const std::complex<_Tp>&); template<typename _Tp> std::complex<_Tp> atanh(const std::complex<_Tp>&); - // DR 595. - template<typename _Tp> _Tp fabs(const std::complex<_Tp>&); template<typename _Tp> inline std::complex<_Tp> @@ -2309,7 +2307,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION acos(const std::complex<_Tp>& __z) { return __complex_acos(__z.__rep()); } #else - /// acos(__z) [8.1.2]. + /// acos(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function cacos, defined // in subclause 7.3.5.1. template<typename _Tp> @@ -2345,7 +2343,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION asin(const std::complex<_Tp>& __z) { return __complex_asin(__z.__rep()); } #else - /// asin(__z) [8.1.3]. + /// asin(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function casin, defined // in subclause 7.3.5.2. template<typename _Tp> @@ -2389,7 +2387,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION atan(const std::complex<_Tp>& __z) { return __complex_atan(__z.__rep()); } #else - /// atan(__z) [8.1.4]. + /// atan(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function catan, defined // in subclause 7.3.5.3. template<typename _Tp> @@ -2425,7 +2423,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION acosh(const std::complex<_Tp>& __z) { return __complex_acosh(__z.__rep()); } #else - /// acosh(__z) [8.1.5]. + /// acosh(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function cacosh, defined // in subclause 7.3.6.1. template<typename _Tp> @@ -2464,7 +2462,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION asinh(const std::complex<_Tp>& __z) { return __complex_asinh(__z.__rep()); } #else - /// asinh(__z) [8.1.6]. + /// asinh(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function casin, defined // in subclause 7.3.6.2. template<typename _Tp> @@ -2508,7 +2506,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION atanh(const std::complex<_Tp>& __z) { return __complex_atanh(__z.__rep()); } #else - /// atanh(__z) [8.1.7]. + /// atanh(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function catanh, defined // in subclause 7.3.6.3. template<typename _Tp> @@ -2518,22 +2516,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif template<typename _Tp> + _GLIBCXX11_DEPRECATED_SUGGEST("std::abs") inline _Tp - /// fabs(__z) [8.1.8]. + /// fabs(__z) TR1 8.1.8 [tr.c99.cmplx.fabs] // Effects: Behaves the same as C99 function cabs, defined // in subclause 7.3.8.1. fabs(const std::complex<_Tp>& __z) { return std::abs(__z); } - /// Additional overloads [8.1.9]. + // Additional overloads C++11 26.4.9 [cmplx.over] + template<typename _Tp> inline typename __gnu_cxx::__promote<_Tp>::__type arg(_Tp __x) { typedef typename __gnu_cxx::__promote<_Tp>::__type __type; #if (_GLIBCXX11_USE_C99_MATH && !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) - return std::signbit(__x) ? __type(3.1415926535897932384626433832795029L) - : __type(); + return __builtin_signbit(__type(__x)) + ? __type(3.1415926535897932384626433832795029L) : __type(); #else return std::arg(std::complex<__type>(__x)); #endif diff --git a/libstdc++-v3/include/std/deque b/libstdc++-v3/include/std/deque index 8fd7300..2badab8 100644 --- a/libstdc++-v3/include/std/deque +++ b/libstdc++-v3/include/std/deque @@ -72,6 +72,7 @@ #define __glibcxx_want_algorithm_default_value_type #define __glibcxx_want_allocator_traits_is_always_equal +#define __glibcxx_want_containers_ranges #define __glibcxx_want_erase_if #define __glibcxx_want_nonmember_container_access #include <bits/version.h> diff --git a/libstdc++-v3/include/std/expected b/libstdc++-v3/include/std/expected index 5dc1dfb..60f1565 100644 --- a/libstdc++-v3/include/std/expected +++ b/libstdc++-v3/include/std/expected @@ -1169,13 +1169,13 @@ namespace __expected return !__y.has_value() && bool(__x.error() == __y.error()); } - template<typename _Up> + template<typename _Up, same_as<_Tp> _Vp> requires (!__expected::__is_expected<_Up>) && requires (const _Tp& __t, const _Up& __u) { { __t == __u } -> convertible_to<bool>; } friend constexpr bool - operator==(const expected& __x, const _Up& __v) + operator==(const expected<_Vp, _Er>& __x, const _Up& __v) noexcept(noexcept(bool(*__x == __v))) { return __x.has_value() && bool(*__x == __v); } diff --git a/libstdc++-v3/include/std/flat_map b/libstdc++-v3/include/std/flat_map index 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 2e9319c..46bd5d5 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> // back_insert_iterator, 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 @@ -80,12 +80,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @cond undocumented namespace __format { - // Type-erased character sink. + // STATICALLY-WIDEN, see C++20 [time.general] + // It doesn't matter for format strings (which can only be char or wchar_t) + // but this returns the narrow string for anything that isn't wchar_t. This + // is done because const char* can be inserted into any ostream type, and + // will be widened at runtime if necessary. + template<typename _CharT> + consteval auto + _Widen(const char* __narrow, const wchar_t* __wide) + { + if constexpr (is_same_v<_CharT, wchar_t>) + return __wide; + else + return __narrow; + } +#define _GLIBCXX_WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define _GLIBCXX_WIDEN(S) _GLIBCXX_WIDEN_(_CharT, S) + + // Size for stack located buffer + template<typename _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 _Out, typename _CharT> class _Padding_sink; + // Output iterator that writes to a type-erase character sink. template<typename _CharT> class _Sink_iter; + // An unspecified output iterator type used in the `formattable` concept. + template<typename _CharT> + struct _Iter_for + { using type = back_insert_iterator<basic_string<_CharT>>; }; + template<typename _CharT> using __format_context = basic_format_context<_Sink_iter<_CharT>, _CharT>; @@ -104,6 +133,7 @@ namespace __format template<typename, typename...> friend struct std::basic_format_string; }; + } // namespace __format /// @endcond @@ -442,36 +472,33 @@ namespace __format return {0, nullptr}; } - enum _Pres_type { + enum class _Pres_type : unsigned char { _Pres_none = 0, // Default type (not valid for integer presentation types). + _Pres_s = 1, // For strings, bool, ranges // Presentation types for integral types (including bool and charT). - _Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c, - // Presentation types for floating-point types. - _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, _Pres_g, _Pres_G, - _Pres_p = 0, _Pres_P, // For pointers. - _Pres_s = 0, // For strings and bool. - _Pres_esc = 0xf, // For strings and charT. - }; - - enum _Align { - _Align_default, - _Align_left, - _Align_right, - _Align_centre, + _Pres_c = 2, _Pres_x, _Pres_X, _Pres_d, _Pres_o, _Pres_b, _Pres_B, + // Presentation types for floating-point types + _Pres_g = 1, _Pres_G, _Pres_a, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, + // For pointers, the value are same as hexadecimal presentations for integers + _Pres_p = _Pres_x, _Pres_P = _Pres_X, + _Pres_max = 0xf, }; + using enum _Pres_type; - enum _Sign { + enum class _Sign : unsigned char { _Sign_default, _Sign_plus, _Sign_minus, // XXX does this need to be distinct from _Sign_default? _Sign_space, }; + using enum _Sign; - enum _WidthPrec { + enum _WidthPrec : unsigned char { _WP_none, // No width/prec specified. _WP_value, // Fixed width/prec specified. _WP_from_arg // Use a formatting argument for width/prec. }; + using enum _WidthPrec; template<typename _Context> size_t @@ -483,9 +510,17 @@ namespace __format constexpr bool __is_xdigit(char __c) { return std::__detail::__from_chars_alnum_to_val(__c) < 16; } + // Used to make _Spec a non-C++98 POD, so the tail-padding is used. + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#pod + struct _SpecBase + { }; + template<typename _CharT> - struct _Spec + struct _Spec : _SpecBase { + unsigned short _M_width; + unsigned short _M_prec; + char32_t _M_fill = ' '; _Align _M_align : 2; _Sign _M_sign : 2; unsigned _M_alt : 1; @@ -493,12 +528,11 @@ namespace __format unsigned _M_zero_fill : 1; _WidthPrec _M_width_kind : 2; _WidthPrec _M_prec_kind : 2; + unsigned _M_debug : 1; _Pres_type _M_type : 4; - unsigned _M_reserved : 1; - unsigned _M_reserved2 : 16; - unsigned short _M_width; - unsigned short _M_prec; - char32_t _M_fill = ' '; + unsigned _M_reserved : 8; + // This class has 8 bits of tail padding, that can be used by + // derived classes. using iterator = typename basic_string_view<_CharT>::iterator; @@ -517,42 +551,48 @@ namespace __format // pre: __first != __last constexpr iterator _M_parse_fill_and_align(iterator __first, iterator __last) noexcept + { return _M_parse_fill_and_align(__first, __last, "{"); } + + // pre: __first != __last + constexpr iterator + _M_parse_fill_and_align(iterator __first, iterator __last, string_view __not_fill) noexcept { - if (*__first != '{') + for (char __c : __not_fill) + if (*__first == static_cast<_CharT>(__c)) + return __first; + + using namespace __unicode; + if constexpr (__literal_encoding_is_unicode<_CharT>()) { - using namespace __unicode; - if constexpr (__literal_encoding_is_unicode<_CharT>()) - { - // Accept any UCS scalar value as fill character. - _Utf32_view<ranges::subrange<iterator>> __uv({__first, __last}); - if (!__uv.empty()) - { - auto __beg = __uv.begin(); - char32_t __c = *__beg++; - if (__is_scalar_value(__c)) - if (auto __next = __beg.base(); __next != __last) - if (_Align __align = _S_align(*__next)) - { - _M_fill = __c; - _M_align = __align; - return ++__next; - } - } - } - else if (__last - __first >= 2) - if (_Align __align = _S_align(__first[1])) - { - _M_fill = *__first; - _M_align = __align; - return __first + 2; - } + // Accept any UCS scalar value as fill character. + _Utf32_view<ranges::subrange<iterator>> __uv({__first, __last}); + if (!__uv.empty()) + { + auto __beg = __uv.begin(); + char32_t __c = *__beg++; + if (__is_scalar_value(__c)) + if (auto __next = __beg.base(); __next != __last) + if (_Align __align = _S_align(*__next); __align != _Align_default) + { + _M_fill = __c; + _M_align = __align; + return ++__next; + } + } + } + else if (__last - __first >= 2) + 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])) - { - _M_fill = ' '; - _M_align = __align; - return __first + 1; - } + if (_Align __align = _S_align(__first[0]); __align != _Align_default) + { + _M_fill = ' '; + _M_align = __align; + return __first + 1; } return __first; } @@ -573,7 +613,7 @@ namespace __format constexpr iterator _M_parse_sign(iterator __first, iterator) noexcept { - if (_Sign __sign = _S_sign(*__first)) + if (_Sign __sign = _S_sign(*__first); __sign != _Sign_default) { _M_sign = __sign; return __first + 1; @@ -841,13 +881,336 @@ 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); } + 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 { + _Term_none, + _Term_quote, + _Term_apos, + }; + using enum _Term_char; + + template<typename _CharT> + struct _Escapes + { + using _Str_view = basic_string_view<_CharT>; + + static consteval + _Str_view _S_all() + { return _GLIBCXX_WIDEN("\t\\t\n\\n\r\\r\\\\\\\"\\\"'\\'\\u\\x"); } + + static consteval + _Str_view _S_tab() + { return _S_all().substr(0, 3); } + + static consteval + _Str_view _S_newline() + { return _S_all().substr(3, 3); } + + static consteval + _Str_view _S_return() + { return _S_all().substr(6, 3); } + + static consteval + _Str_view _S_bslash() + { return _S_all().substr(9, 3); } + + static consteval + _Str_view _S_quote() + { return _S_all().substr(12, 3); } + + static consteval + _Str_view _S_apos() + { return _S_all().substr(15, 3); } + + static consteval + _Str_view _S_u() + { return _S_all().substr(18, 2); } + + 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> + struct _Separators + { + using _Str_view = basic_string_view<_CharT>; + + static consteval + _Str_view _S_all() + { return _GLIBCXX_WIDEN("[]{}(), : "); } + + static consteval + _Str_view _S_squares() + { return _S_all().substr(0, 2); } + + static consteval + _Str_view _S_braces() + { return _S_all().substr(2, 2); } + + static consteval + _Str_view _S_parens() + { return _S_all().substr(4, 2); } + + static consteval + _Str_view _S_comma() + { return _S_all().substr(6, 2); } + + static consteval + _Str_view _S_colon() + { return _S_all().substr(8, 2); } + }; + + template<typename _CharT> + constexpr bool __should_escape_ascii(_CharT __c, _Term_char __term) + { + using _Esc = _Escapes<_CharT>; + switch (__c) + { + case _Esc::_S_tab()[0]: + case _Esc::_S_newline()[0]: + case _Esc::_S_return()[0]: + case _Esc::_S_bslash()[0]: + return true; + case _Esc::_S_quote()[0]: + return __term == _Term_quote; + case _Esc::_S_apos()[0]: + return __term == _Term_apos; + default: + return (__c >= 0 && __c < 0x20) || __c == 0x7f; + }; + } + + // @pre __c <= 0x10FFFF + constexpr bool __should_escape_unicode(char32_t __c, bool __prev_esc) + { + if (__unicode::__should_escape_category(__c)) + return __c != U' '; + if (!__prev_esc) + return false; + return __unicode::__grapheme_cluster_break_property(__c) + == __unicode::_Gcb_property::_Gcb_Extend; + } + + using uint_least32_t = __UINT_LEAST32_TYPE__; + template<typename _Out, typename _CharT> + _Out + __write_escape_seq(_Out __out, uint_least32_t __val, + basic_string_view<_CharT> __prefix) + { + using _Str_view = basic_string_view<_CharT>; + constexpr size_t __max = 8; + char __buf[__max]; + const string_view __narrow( + __buf, + std::__to_chars_i<uint_least32_t>(__buf, __buf + __max, __val, 16).ptr); + + __out = __format::__write(__out, __prefix); + *__out = _Separators<_CharT>::_S_braces()[0]; + ++__out; + if constexpr (is_same_v<char, _CharT>) + __out = __format::__write(__out, __narrow); +#ifdef _GLIBCXX_USE_WCHAR_T + else + { + _CharT __wbuf[__max]; + const size_t __n = __narrow.size(); + std::__to_wstring_numeric(__narrow.data(), __n, __wbuf); + __out = __format::__write(__out, _Str_view(__wbuf, __n)); + } +#endif + *__out = _Separators<_CharT>::_S_braces()[1]; + return ++__out; + } + + template<typename _Out, typename _CharT> + _Out + __write_escaped_char(_Out __out, _CharT __c) + { + using _UChar = make_unsigned_t<_CharT>; + using _Esc = _Escapes<_CharT>; + switch (__c) + { + case _Esc::_S_tab()[0]: + return __format::__write(__out, _Esc::_S_tab().substr(1, 2)); + case _Esc::_S_newline()[0]: + return __format::__write(__out, _Esc::_S_newline().substr(1, 2)); + case _Esc::_S_return()[0]: + return __format::__write(__out, _Esc::_S_return().substr(1, 2)); + case _Esc::_S_bslash()[0]: + return __format::__write(__out, _Esc::_S_bslash().substr(1, 2)); + case _Esc::_S_quote()[0]: + return __format::__write(__out, _Esc::_S_quote().substr(1, 2)); + 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()); + } + } + + template<typename _CharT, typename _Out> + _Out + __write_escaped_ascii(_Out __out, + basic_string_view<_CharT> __str, + _Term_char __term) + { + using _Str_view = basic_string_view<_CharT>; + auto __first = __str.begin(); + auto const __last = __str.end(); + while (__first != __last) + { + auto __print = __first; + // assume anything outside ASCII is printable + while (__print != __last + && !__format::__should_escape_ascii(*__print, __term)) + ++__print; + + if (__print != __first) + __out = __format::__write(__out, _Str_view(__first, __print)); + + if (__print == __last) + return __out; + + __first = __print; + __out = __format::__write_escaped_char(__out, *__first); + ++__first; + } + return __out; + } + + template<typename _CharT, typename _Out> + _Out + __write_escaped_unicode(_Out __out, + basic_string_view<_CharT> __str, + _Term_char __term) + { + using _Str_view = basic_string_view<_CharT>; + using _UChar = make_unsigned_t<_CharT>; + using _Esc = _Escapes<_CharT>; + + static constexpr char32_t __replace = U'\uFFFD'; + static constexpr _Str_view __replace_rep = [] + { + // N.B. "\uFFFD" is ill-formed if encoding is not unicode. + if constexpr (is_same_v<char, _CharT>) + return "\xEF\xBF\xBD"; + else + return L"\xFFFD"; + }(); + + __unicode::_Utf_view<char32_t, _Str_view> __v(std::move(__str)); + auto __first = __v.begin(); + auto const __last = __v.end(); + + bool __prev_esc = true; + while (__first != __last) + { + bool __esc_ascii = false; + bool __esc_unicode = false; + bool __esc_replace = false; + auto __should_escape = [&](auto const& __it) + { + if (*__it <= 0x7f) + return __esc_ascii + = __format::__should_escape_ascii(*__it.base(), __term); + if (__format::__should_escape_unicode(*__it, __prev_esc)) + return __esc_unicode = true; + if (*__it == __replace) + { + _Str_view __units(__it.base(), __it._M_units()); + return __esc_replace = (__units != __replace_rep); + } + return false; + }; + + auto __print = __first; + while (__print != __last && !__should_escape(__print)) + { + __prev_esc = false; + ++__print; + } + + if (__print != __first) + __out = __format::__write(__out, _Str_view(__first.base(), __print.base())); + + if (__print == __last) + return __out; + + __first = __print; + if (__esc_ascii) + __out = __format::__write_escaped_char(__out, *__first.base()); + else if (__esc_unicode) + __out = __format::__write_escape_seq(__out, *__first, _Esc::_S_u()); + else // __esc_replace + for (_CharT __c : _Str_view(__first.base(), __first._M_units())) + __out = __format::__write_escape_seq(__out, + static_cast<_UChar>(__c), + _Esc::_S_x()); + __prev_esc = true; + ++__first; + + } + return __out; + } + + template<typename _CharT, typename _Out> + _Out + __write_escaped(_Out __out, basic_string_view<_CharT> __str, _Term_char __term) + { + __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); + else if constexpr (is_same_v<char, _CharT> + && __unicode::__literal_encoding_is_extended_ascii()) + __out = __format::__write_escaped_ascii(__out, __str, __term); + else + // TODO Handle non-ascii extended encoding + __out = __format::__write_escaped_ascii(__out, __str, __term); + + return __format::__write(__out, _Escapes<_CharT>::_S_term(__term)); + } + // A lightweight optional<locale>. struct _Optional_locale { @@ -924,6 +1287,13 @@ namespace __format template<__char _CharT> struct __formatter_str { + __formatter_str() = default; + + constexpr + __formatter_str(_Spec<_CharT> __spec) noexcept + : _M_spec(__spec) + { } + constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) { @@ -960,11 +1330,14 @@ namespace __format return __first; if (*__first == 's') - ++__first; -#if __cpp_lib_format_ranges + { + __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 @@ -980,40 +1353,115 @@ namespace __format format(basic_string_view<_CharT> __s, basic_format_context<_Out, _CharT>& __fc) const { - if (_M_spec._M_type == _Pres_esc) - { - // TODO: C++23 escaped string presentation - } + 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 __format::__write(__fc.out(), __s); - size_t __estimated_width; - if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>()) + 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); + } + + 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); + + 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); + + // N.B. [tab:format.type.string] defines '?' as + // Copies the escaped string ([format.string.escaped]) to the output, + // so precision seem to appy to escaped string. + _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth, __maxwidth); + __format::__write_escaped(__sink.out(), __s, _Term_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> + _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 (!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>) { - if (_M_spec._M_prec_kind != _WP_none) + const size_t __n(ranges::distance(__rg)); + 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>) { - size_t __prec = _M_spec._M_get_precision(__fc); - __estimated_width = __unicode::__truncate(__s, __prec); + _CharT __buf[__format::__stackbuf_size<_CharT>]; + ranges::copy_n(ranges::begin(__rg), __w, __buf); + return _M_format_escaped(_String_view(__buf, __n), __fc); } + else if constexpr (ranges::random_access_range<_Rg>) + { + ranges::iterator_t<_Rg> __first = ranges::begin(__rg); + 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 - __estimated_width = __unicode::__field_width(__s); + { + // N.B. preserve the computed size + ranges::subrange __sub(__rg, __n); + return _M_format_escaped(_String(from_range, __sub), __fc); + } } else - { - __s = __s.substr(0, _M_spec._M_get_precision(__fc)); - __estimated_width = __s.size(); - } - - return __format::__write_padded_as_spec(__s, __estimated_width, - __fc, _M_spec); + return _M_format_escaped(_String(from_range, __rg), __fc); } -#if __cpp_lib_format_ranges constexpr void set_debug_format() noexcept - { _M_spec._M_type = _Pres_esc; } + { _M_spec._M_debug = true; } #endif private: @@ -1029,6 +1477,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) { @@ -1116,15 +1574,15 @@ 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; -#if __cpp_lib_format_ranges +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED case '?': if (__type == _AsChar) { - __spec._M_type = _Pres_esc; + __spec._M_debug = true; ++__first; } #endif @@ -1145,7 +1603,8 @@ namespace __format { auto __end = _M_do_parse(__pc, _AsBool); if (_M_spec._M_type == _Pres_s) - if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill) + if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt + || _M_spec._M_zero_fill) __throw_format_error("format error: format-spec contains " "invalid formatting options for " "'bool'"); @@ -1154,8 +1613,9 @@ namespace __format else if constexpr (__char<_Tp>) { auto __end = _M_do_parse(__pc, _AsChar); - if (_M_spec._M_type == _Pres_c || _M_spec._M_type == _Pres_esc) - if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill + if (_M_spec._M_type == _Pres_c) + if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt + || _M_spec._M_zero_fill /* XXX should be invalid? || _M_spec._M_localized */) __throw_format_error("format error: format-spec contains " "invalid formatting options for " @@ -1267,26 +1727,35 @@ 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); + + __width += 2; + if (_M_spec._M_get_width(__fc) <= __width) + return __format::__write_escaped(__fc.out(), __in, _Term_apos); + + _CharT __buf[12]; + _Fixedbuf_sink<_CharT> __sink(__buf); + __format::__write_escaped(__sink.out(), __in, _Term_apos); + + __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); } template<typename _Int> @@ -1402,20 +1871,24 @@ namespace __format _Spec<_CharT> _M_spec{}; }; +#ifdef __BFLT16_DIG__ + using __bflt16_t = decltype(0.0bf16); +#endif + // Decide how 128-bit floating-point types should be formatted (or not). - // When supported, the typedef __format::__float128_t is the type that - // format arguments should be converted to for storage in basic_format_arg. + // When supported, the typedef __format::__flt128_t is the type that format + // arguments should be converted to before passing them to __formatter_fp. // Define the macro _GLIBCXX_FORMAT_F128 to say they're supported. - // _GLIBCXX_FORMAT_F128=1 means __float128, _Float128 etc. will be formatted - // by converting them to long double (or __ieee128 for powerpc64le). - // _GLIBCXX_FORMAT_F128=2 means basic_format_arg needs to enable explicit - // support for _Float128, rather than formatting it as another type. + // The __float128, _Float128 will be formatted by converting them to: + // __ieee128 (same as __float128) when _GLIBCXX_FORMAT_F128=1, + // long double when _GLIBCXX_FORMAT_F128=2, + // _Float128 when _GLIBCXX_FORMAT_F128=3. #undef _GLIBCXX_FORMAT_F128 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // Format 128-bit floating-point types using __ieee128. - using __float128_t = __ieee128; + using __flt128_t = __ieee128; # define _GLIBCXX_FORMAT_F128 1 #ifdef __LONG_DOUBLE_IEEE128__ @@ -1449,14 +1922,14 @@ namespace __format #elif defined _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128 // Format 128-bit floating-point types using long double. - using __float128_t = long double; -# define _GLIBCXX_FORMAT_F128 1 + using __flt128_t = long double; +# define _GLIBCXX_FORMAT_F128 2 #elif __FLT128_DIG__ && defined(_GLIBCXX_HAVE_FLOAT128_MATH) // Format 128-bit floating-point types using _Float128. - using __float128_t = _Float128; -# define _GLIBCXX_FORMAT_F128 2 + using __flt128_t = _Float128; +# define _GLIBCXX_FORMAT_F128 3 # if __cplusplus == 202002L // These overloads exist in the library, but are not declared for C++20. @@ -1925,9 +2398,16 @@ namespace __format const size_t __r = __str.size() - __e; // Length of remainder. auto __overwrite = [&](_CharT* __p, size_t) { // Apply grouping to the digits before the radix or exponent. - auto __end = std::__add_grouping(__p, __np.thousands_sep(), + int __off = 0; + if (auto __c = __str.front(); __c == '-' || __c == '+' || __c == ' ') + { + *__p = __c; + __off = 1; + } + auto __end = std::__add_grouping(__p + __off, __np.thousands_sep(), __grp.data(), __grp.size(), - __str.data(), __str.data() + __e); + __str.data() + __off, + __str.data() + __e); if (__r) // If there's a fractional part or exponent { if (__d != __str.npos) @@ -1950,6 +2430,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 @@ -1969,22 +2593,16 @@ 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) - { - // TODO - return __fc.out(); - } else return _M_f.format(static_cast<make_unsigned_t<_CharT>>(__u), __fc); } -#if __cpp_lib_format_ranges +#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: @@ -2008,22 +2626,16 @@ 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) - { - // TODO - return __fc.out(); - } else return _M_f.format(static_cast<unsigned char>(__u), __fc); } -#if __cpp_lib_format_ranges +#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: @@ -2050,7 +2662,7 @@ namespace __format format(_CharT* __u, basic_format_context<_Out, _CharT>& __fc) const { return _M_f.format(__u, __fc); } -#if __cpp_lib_format_ranges +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } #endif @@ -2075,7 +2687,7 @@ namespace __format basic_format_context<_Out, _CharT>& __fc) const { return _M_f.format(__u, __fc); } -#if __cpp_lib_format_ranges +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } #endif @@ -2099,7 +2711,7 @@ namespace __format basic_format_context<_Out, _CharT>& __fc) const { return _M_f.format({__u, _Nm}, __fc); } -#if __cpp_lib_format_ranges +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } #endif @@ -2123,7 +2735,7 @@ namespace __format basic_format_context<_Out, char>& __fc) const { return _M_f.format(__u, __fc); } -#if __cpp_lib_format_ranges +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } #endif @@ -2148,7 +2760,7 @@ namespace __format basic_format_context<_Out, wchar_t>& __fc) const { return _M_f.format(__u, __fc); } -#if __cpp_lib_format_ranges +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } #endif @@ -2173,7 +2785,7 @@ namespace __format basic_format_context<_Out, char>& __fc) const { return _M_f.format(__u, __fc); } -#if __cpp_lib_format_ranges +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } #endif @@ -2198,7 +2810,7 @@ namespace __format basic_format_context<_Out, wchar_t>& __fc) const { return _M_f.format(__u, __fc); } -#if __cpp_lib_format_ranges +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } #endif @@ -2364,8 +2976,8 @@ namespace __format }; #endif -#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 == 1 - // Reuse __formatter_fp<C>::format<__float128_t, Out> for _Float128. +#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 + // Use __formatter_fp<C>::format<__format::__flt128_t, Out> for _Float128. template<__format::__char _CharT> struct formatter<_Float128, _CharT> { @@ -2379,17 +2991,45 @@ namespace __format template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(_Float128 __u, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f.format((__format::__float128_t)__u, __fc); } + { return _M_f.format((__format::__flt128_t)__u, __fc); } private: __format::__formatter_fp<_CharT> _M_f; }; #endif +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 > 1 + // Reuse __formatter_fp<C>::format<__format::__flt128_t, Out> for __float128. + // This formatter is not declared if _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT is true, + // as __float128 when present is same type as __ieee128, which may be same as + // long double. + template<__format::__char _CharT> + struct formatter<__float128, _CharT> + { + formatter() = default; + + [[__gnu__::__always_inline__]] + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__float128 __u, basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format((__format::__flt128_t)__u, __fc); } + + private: + __format::__formatter_fp<_CharT> _M_f; + + static_assert( !is_same_v<__float128, long double>, + "This specialization should not be used for long double" ); + }; +#endif + #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) // Reuse __formatter_fp<C>::format<float, Out> for bfloat16_t. template<__format::__char _CharT> - struct formatter<__gnu_cxx::__bfloat16_t, _CharT> + struct formatter<__format::__bflt16_t, _CharT> { formatter() = default; @@ -2420,120 +3060,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> @@ -2552,7 +3087,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> @@ -2571,98 +3106,38 @@ namespace __format { return _M_f.format(nullptr, __fc); } private: - formatter<const void*, _CharT> _M_f; + __format::__formatter_ptr<_CharT> _M_f; }; /// @} -#if defined _GLIBCXX_USE_WCHAR_T && __cpp_lib_format_ranges +#if defined _GLIBCXX_USE_WCHAR_T && __glibcxx_format_ranges // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3944. Formatters converting sequences of char to sequences of wchar_t - namespace __format { struct __disabled; } + struct __formatter_disabled + { + __formatter_disabled() = delete; // Cannot format char sequence to wchar_t + __formatter_disabled(const __formatter_disabled&) = delete; + __formatter_disabled& operator=(const __formatter_disabled&) = delete; + }; - // std::formatter<__disabled, C> uses the primary template, which is disabled. template<> struct formatter<char*, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<> struct formatter<const char*, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<size_t _Nm> struct formatter<char[_Nm], wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<class _Traits, class _Allocator> struct formatter<basic_string<char, _Traits, _Allocator>, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<class _Traits> struct formatter<basic_string_view<char, _Traits>, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; -#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>; - -} // namespace __format -/// @endcond - -// Concept std::formattable was introduced by P2286R8 "Formatting Ranges", -// but we can't guard it with __cpp_lib_format_ranges until we define that! -#if __cplusplus > 202002L - // [format.formattable], concept formattable - template<typename _Tp, typename _CharT> - concept formattable - = __format::__formattable_impl<remove_reference_t<_Tp>, _CharT>; + : private __formatter_disabled { }; #endif -#if __cpp_lib_format_ranges - /// @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>; - - template<typename _Rg, typename _CharT> - using __maybe_const_range - = conditional_t<__const_formattable_range<_Rg, _CharT>, const _Rg, _Rg>; -} // namespace __format - /// @endcond -#endif // format_ranges - /// An iterator after the last character written, and the number of /// characters that would have been written. template<typename _Out> @@ -2730,6 +3205,10 @@ namespace __format auto _M_reserve(size_t __n) const { return _M_sink->_M_reserve(__n); } + + bool + _M_discarding() const + { return _M_sink->_M_discarding(); } }; // Abstract base class for type-erased character sinks. @@ -2849,6 +3328,11 @@ namespace __format _M_bump(size_t __n) { _M_next += __n; } + // Returns true if the _Sink is discarding incoming characters. + virtual bool + _M_discarding() const + { return false; } + public: _Sink(const _Sink&) = delete; _Sink& operator=(const _Sink&) = delete; @@ -2859,12 +3343,38 @@ namespace __format { return _Sink_iter<_CharT>(*this); } }; + + template<typename _CharT> + class _Fixedbuf_sink final : public _Sink<_CharT> + { + void + _M_overflow() override + { + __glibcxx_assert(false); + this->_M_rewind(); + } + + public: + [[__gnu__::__always_inline__]] + constexpr explicit + _Fixedbuf_sink(span<_CharT> __buf) + : _Sink<_CharT>(__buf) + { } + + constexpr basic_string_view<_CharT> + view() const + { + auto __s = this->_M_used(); + return basic_string_view<_CharT>(__s.data(), __s.size()); + } + }; + // A sink with an internal buffer. This is used to implement concrete sinks. template<typename _CharT> class _Buf_sink : public _Sink<_CharT> { protected: - _CharT _M_buf[32 * sizeof(void*) / sizeof(_CharT)]; + _CharT _M_buf[__stackbuf_size<_CharT>]; [[__gnu__::__always_inline__]] constexpr @@ -2878,12 +3388,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 @@ -2955,6 +3465,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? @@ -2980,7 +3501,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()) @@ -2991,6 +3512,13 @@ namespace __format } return __s; } + + basic_string_view<_CharT> + view() + { + auto __span = _M_span(); + return basic_string_view<_CharT>(__span.data(), __span.size()); + } }; template<typename _CharT, typename _Alloc = allocator<_CharT>> @@ -2998,9 +3526,7 @@ namespace __format = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>; // template<typename _CharT, typename _Alloc = allocator<_CharT>> - // using _Vec_sink = _Seq_sink<vector<_CharT, _Alloc>>; - - // A sink that writes to an output iterator. + // 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> @@ -3032,6 +3558,14 @@ namespace __format _M_count += __s.size(); } + bool + _M_discarding() const override + { + // format_to_n return total number of characters, that would be written, + // see C++20 [format.functions] p20 + return false; + } + public: [[__gnu__::__always_inline__]] explicit @@ -3094,6 +3628,14 @@ namespace __format } } + bool + _M_discarding() const override + { + // format_to_n return total number of characters, that would be written, + // see C++20 [format.functions] p20 + return false; + } + typename _Sink<_CharT>::_Reservation _M_reserve(size_t __n) final { @@ -3168,20 +3710,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 @@ -3207,6 +3931,12 @@ namespace __format double _M_dbl; #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // No long double if it's ambiguous. long double _M_ldbl; +#else + __ibm128 _M_ibm128; + __ieee128 _M_ieee128; +#endif +#ifdef __SIZEOF_FLOAT128__ + __float128 _M_float128; #endif const _CharT* _M_str; basic_string_view<_CharT> _M_sv; @@ -3216,11 +3946,17 @@ namespace __format __int128 _M_i128; unsigned __int128 _M_u128; #endif -#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT - __ieee128 _M_f128; - __ibm128 _M_ibm128; -#elif _GLIBCXX_FORMAT_F128 == 2 - __float128_t _M_f128; +#ifdef __BFLT16_DIG__ + __bflt16_t _M_bf16; +#endif +#ifdef __FLT16_DIG__ + _Float16 _M_f16; +#endif +#ifdef __FLT32_DIG__ + _Float32 _M_f32; +#endif +#ifdef __FLT64_DIG__ + _Float64 _M_f64; #endif }; @@ -3258,10 +3994,14 @@ namespace __format else if constexpr (is_same_v<_Tp, long double>) return __u._M_ldbl; #else - else if constexpr (is_same_v<_Tp, __ieee128>) - return __u._M_f128; else if constexpr (is_same_v<_Tp, __ibm128>) return __u._M_ibm128; + else if constexpr (is_same_v<_Tp, __ieee128>) + return __u._M_ieee128; +#endif +#ifdef __SIZEOF_FLOAT128__ + else if constexpr (is_same_v<_Tp, __float128>) + return __u._M_float128; #endif else if constexpr (is_same_v<_Tp, const _CharT*>) return __u._M_str; @@ -3275,9 +4015,21 @@ namespace __format else if constexpr (is_same_v<_Tp, unsigned __int128>) return __u._M_u128; #endif -#if _GLIBCXX_FORMAT_F128 == 2 - else if constexpr (is_same_v<_Tp, __float128_t>) - return __u._M_f128; +#ifdef __BFLT16_DIG__ + else if constexpr (is_same_v<_Tp, __bflt16_t>) + return __u._M_bf16; +#endif +#ifdef __FLT16_DIG__ + else if constexpr (is_same_v<_Tp, _Float16>) + return __u._M_f16; +#endif +#ifdef __FLT32_DIG__ + else if constexpr (is_same_v<_Tp, _Float32>) + return __u._M_f32; +#endif +#ifdef __FLT64_DIG__ + else if constexpr (is_same_v<_Tp, _Float64>) + return __u._M_f64; #endif else if constexpr (derived_from<_Tp, _HandleBase>) return static_cast<_Tp&>(__u._M_handle); @@ -3456,36 +4208,25 @@ namespace __format else if constexpr (is_same_v<_Td, __ieee128>) return type_identity<__ieee128>(); #endif - -#if defined(__FLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) - else if constexpr (is_same_v<_Td, _Float16>) - return type_identity<float>(); +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 + else if constexpr (is_same_v<_Td, __float128>) + return type_identity<__float128>(); #endif - -#if defined(__BFLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) - else if constexpr (is_same_v<_Td, decltype(0.0bf16)>) - return type_identity<float>(); +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Td, __format::__bflt16_t>) + return type_identity<__format::__bflt16_t>(); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Td, _Float16>) + return type_identity<_Float16>(); #endif - #if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) else if constexpr (is_same_v<_Td, _Float32>) - return type_identity<float>(); + return type_identity<_Float32>(); #endif - #if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) else if constexpr (is_same_v<_Td, _Float64>) - return type_identity<double>(); -#endif - -#if _GLIBCXX_FORMAT_F128 -# if __FLT128_DIG__ - else if constexpr (is_same_v<_Td, _Float128>) - return type_identity<__format::__float128_t>(); -# endif -# if __SIZEOF_FLOAT128__ - else if constexpr (is_same_v<_Td, __float128>) - return type_identity<__format::__float128_t>(); -# endif + return type_identity<_Float64>(); #endif else if constexpr (__is_specialization_of<_Td, basic_string_view> || __is_specialization_of<_Td, basic_string>) @@ -3541,7 +4282,27 @@ namespace __format else if constexpr (is_same_v<_Tp, __ibm128>) return _Arg_ibm128; else if constexpr (is_same_v<_Tp, __ieee128>) - return _Arg_f128; + return _Arg_ieee128; +#endif +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 + else if constexpr (is_same_v<_Tp, __float128>) + return _Arg_float128; +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Tp, __format::__bflt16_t>) + return _Arg_bf16; +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Tp, _Float16>) + return _Arg_f16; +#endif +#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Tp, _Float32>) + return _Arg_f32; +#endif +#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + else if constexpr (is_same_v<_Tp, _Float64>) + return _Arg_f64; #endif else if constexpr (is_same_v<_Tp, const _CharT*>) return _Arg_str; @@ -3555,11 +4316,6 @@ namespace __format else if constexpr (is_same_v<_Tp, unsigned __int128>) return _Arg_u128; #endif - -#if _GLIBCXX_FORMAT_F128 == 2 - else if constexpr (is_same_v<_Tp, __format::__float128_t>) - return _Arg_f128; -#endif else if constexpr (is_same_v<_Tp, handle>) return _Arg_handle; } @@ -3632,13 +4388,33 @@ namespace __format #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT case _Arg_ldbl: return std::forward<_Visitor>(__vis)(_M_val._M_ldbl); +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 + case _Arg_float128: + return std::forward<_Visitor>(__vis)(_M_val._M_float128); +#endif #else - case _Arg_f128: - return std::forward<_Visitor>(__vis)(_M_val._M_f128); case _Arg_ibm128: return std::forward<_Visitor>(__vis)(_M_val._M_ibm128); + case _Arg_ieee128: + return std::forward<_Visitor>(__vis)(_M_val._M_ieee128); +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + case _Arg_bf16: + return std::forward<_Visitor>(__vis)(_M_val._M_bf16); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + case _Arg_f16: + return std::forward<_Visitor>(__vis)(_M_val._M_f16); +#endif +#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + case _Arg_f32: + return std::forward<_Visitor>(__vis)(_M_val._M_f32); #endif +#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + case _Arg_f64: + return std::forward<_Visitor>(__vis)(_M_val._M_f64); #endif +#endif // __glibcxx_to_chars case _Arg_str: return std::forward<_Visitor>(__vis)(_M_val._M_str); case _Arg_sv: @@ -3656,14 +4432,7 @@ namespace __format case _Arg_u128: return std::forward<_Visitor>(__vis)(_M_val._M_u128); #endif - -#if _GLIBCXX_FORMAT_F128 == 2 - case _Arg_f128: - return std::forward<_Visitor>(__vis)(_M_val._M_f128); -#endif - default: - // _Arg_f16 etc. __builtin_unreachable(); } } @@ -3675,17 +4444,17 @@ namespace __format return _M_visit([&__vis]<typename _Tp>(_Tp& __val) -> decltype(auto) { constexpr bool __user_facing = __is_one_of<_Tp, - monostate, bool, _CharT, - int, unsigned int, long long int, unsigned long long int, - float, double, long double, - const _CharT*, basic_string_view<_CharT>, - const void*, handle>::value; + monostate, bool, _CharT, + int, unsigned int, long long int, unsigned long long int, + float, double, long double, + const _CharT*, basic_string_view<_CharT>, + const void*, handle>::value; if constexpr (__user_facing) return std::forward<_Visitor>(__vis)(__val); else { - handle __h(__val); - return std::forward<_Visitor>(__vis)(__h); + handle __h(__val); + return std::forward<_Visitor>(__vis)(__h); } }, __type); } @@ -3749,7 +4518,7 @@ namespace __format { __UINT64_TYPE__ __packed_types = 0; for (auto __i = __types.rbegin(); __i != __types.rend(); ++__i) - __packed_types = (__packed_types << _Bits) | *__i; + __packed_types = (__packed_types << _Bits) | (unsigned)*__i; return __packed_types; } } // namespace __format @@ -3762,7 +4531,7 @@ namespace __format static constexpr int _S_packed_type_mask = 0b11111; static constexpr int _S_max_packed_args = 12; - static_assert( __format::_Arg_max_ <= (1 << _S_packed_type_bits) ); + static_assert( (unsigned)__format::_Arg_max_ <= (1u << _S_packed_type_bits) ); template<typename... _Args> using _Store = __format::_Arg_store<_Context, _Args...>; @@ -4713,22 +5482,8 @@ namespace __format } #endif -#if __cpp_lib_format_ranges - // [format.range], formatting of ranges - // [format.range.fmtkind], variable template format_kind - enum class range_format { - disabled, - map, - set, - sequence, - string, - debug_string - }; - +#if __glibcxx_format_ranges // C++ >= 23 && HOSTED /// @cond undocumented - template<typename _Rg> - constexpr auto format_kind = not defined(format_kind<_Rg>); - template<typename _Tp> consteval range_format __fmt_kind() @@ -4758,29 +5513,570 @@ namespace __format template<ranges::input_range _Rg> requires same_as<_Rg, remove_cvref_t<_Rg>> constexpr range_format format_kind<_Rg> = __fmt_kind<_Rg>(); - // [format.range.formatter], class template range_formatter - template<typename _Tp, typename _CharT = char> - requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT> - class range_formatter; // TODO - /// @cond undocumented namespace __format { - // [format.range.fmtdef], class template range-default-formatter - template<range_format _Kind, ranges::input_range _Rg, typename _CharT> - struct __range_default_formatter; // TODO + template<typename _CharT, typename _Out, typename _Callback> + typename basic_format_context<_Out, _CharT>::iterator + __format_padded(basic_format_context<_Out, _CharT>& __fc, + 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>>); + + 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); + } + + 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<size_t _Pos, typename _Tp, typename _CharT> + struct __indexed_formatter_storage + { + constexpr void + _M_parse() + { + basic_format_parse_context<_CharT> __pc({}); + if (_M_formatter.parse(__pc) != __pc.end()) + __format::__failed_to_parse_format_spec(); + } + + template<typename _Out> + void + _M_format(__maybe_const<_Tp, _CharT>& __elem, + basic_format_context<_Out, _CharT>& __fc, + basic_string_view<_CharT> __sep) const + { + if constexpr (_Pos != 0) + __fc.advance_to(__format::__write(__fc.out(), __sep)); + __fc.advance_to(_M_formatter.format(__elem, __fc)); + } + + [[__gnu__::__always_inline__]] + constexpr void + set_debug_format() + { + if constexpr (__has_debug_format<formatter<_Tp, _CharT>>) + _M_formatter.set_debug_format(); + } + + private: + formatter<_Tp, _CharT> _M_formatter; + }; + + template<typename _CharT, typename... _Tps> + class __tuple_formatter + { + using _String_view = basic_string_view<_CharT>; + using _Seps = __format::_Separators<_CharT>; + + public: + constexpr void + set_separator(basic_string_view<_CharT> __sep) noexcept + { _M_sep = __sep; } + + constexpr void + set_brackets(basic_string_view<_CharT> __open, + basic_string_view<_CharT> __close) noexcept + { + _M_open = __open; + _M_close = __close; + } + + // We deviate from standard, that declares this as template accepting + // unconstrained ParseContext type, which seems unimplementable. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { + auto __first = __pc.begin(); + const auto __last = __pc.end(); + __format::_Spec<_CharT> __spec{}; + + auto __finished = [&] + { + if (__first != __last && *__first != '}') + return false; + + _M_spec = __spec; + _M_felems._M_parse(); + _M_felems.set_debug_format(); + return true; + }; + + if (__finished()) + return __first; + + __first = __spec._M_parse_fill_and_align(__first, __last, "{:"); + if (__finished()) + return __first; + + __first = __spec._M_parse_width(__first, __last, __pc); + if (__finished()) + return __first; + + if (*__first == 'n') + { + ++__first; + _M_open = _M_close = _String_view(); + } + else if (*__first == 'm') + { + ++__first; + if constexpr (sizeof...(_Tps) == 2) + { + _M_sep = _Seps::_S_colon(); + _M_open = _M_close = _String_view(); + } + else + __throw_format_error("format error: 'm' specifier requires range" + " of pair or tuple of two elements"); + } + + if (__finished()) + return __first; + + __format::__failed_to_parse_format_spec(); + } + + protected: + template<typename _Tuple, typename _Out, size_t... _Ids> + typename basic_format_context<_Out, _CharT>::iterator + _M_format(_Tuple& __tuple, index_sequence<_Ids...>, + basic_format_context<_Out, _CharT>& __fc) const + { return _M_format_elems(std::get<_Ids>(__tuple)..., __fc); } + + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + _M_format_elems(__maybe_const<_Tps, _CharT>&... __elems, + basic_format_context<_Out, _CharT>& __fc) const + { + return __format::__format_padded( + __fc, _M_spec, + [this, &__elems...](basic_format_context<_Out, _CharT>& __nfc) + { + __nfc.advance_to(__format::__write(__nfc.out(), _M_open)); + _M_felems._M_format(__elems..., __nfc, _M_sep); + return __format::__write(__nfc.out(), _M_close); + }); + } + + private: + template<size_t... _Ids> + struct __formatters_storage + : __indexed_formatter_storage<_Ids, _Tps, _CharT>... + { + template<size_t _Id, typename _Up> + using _Base = __indexed_formatter_storage<_Id, _Up, _CharT>; + + constexpr void + _M_parse() + { + (_Base<_Ids, _Tps>::_M_parse(), ...); + } + + template<typename _Out> + void + _M_format(__maybe_const<_Tps, _CharT>&... __elems, + basic_format_context<_Out, _CharT>& __fc, + _String_view __sep) const + { + (_Base<_Ids, _Tps>::_M_format(__elems, __fc, __sep), ...); + } + + constexpr void + set_debug_format() + { + (_Base<_Ids, _Tps>::set_debug_format(), ...); + } + }; + + template<size_t... _Ids> + static auto + _S_create_storage(index_sequence<_Ids...>) + -> __formatters_storage<_Ids...>; + using _Formatters + = decltype(_S_create_storage(index_sequence_for<_Tps...>())); + + _Spec<_CharT> _M_spec{}; + _String_view _M_open = _Seps::_S_parens().substr(0, 1); + _String_view _M_close = _Seps::_S_parens().substr(1, 1); + _String_view _M_sep = _Seps::_S_comma(); + _Formatters _M_felems; + }; + + template<typename _Tp> + concept __is_map_formattable + = __is_pair<_Tp> || (__is_tuple_v<_Tp> && tuple_size_v<_Tp> == 2); + } // namespace __format /// @endcond + // [format.tuple] Tuple formatter + template<__format::__char _CharT, formattable<_CharT> _Fp, + formattable<_CharT> _Sp> + struct formatter<pair<_Fp, _Sp>, _CharT> + : __format::__tuple_formatter<_CharT, remove_cvref_t<_Fp>, + remove_cvref_t<_Sp>> + { + private: + using __maybe_const_pair + = __conditional_t<formattable<const _Fp, _CharT> + && formattable<const _Sp, _CharT>, + const pair<_Fp, _Sp>, pair<_Fp, _Sp>>; + public: + // We deviate from standard, that declares this as template accepting + // unconstrained FormatContext type, which seems unimplementable. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__maybe_const_pair& __p, + basic_format_context<_Out, _CharT>& __fc) const + { return this->_M_format_elems(__p.first, __p.second, __fc); } + }; + + template<__format::__char _CharT, formattable<_CharT>... _Tps> + struct formatter<tuple<_Tps...>, _CharT> + : __format::__tuple_formatter<_CharT, remove_cvref_t<_Tps>...> + { + private: + using __maybe_const_tuple + = __conditional_t<(formattable<const _Tps, _CharT> && ...), + const tuple<_Tps...>, tuple<_Tps...>>; + public: + // We deviate from standard, that declares this as template accepting + // unconstrained FormatContext type, which seems unimplementable. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__maybe_const_tuple& __t, + basic_format_context<_Out, _CharT>& __fc) const + { return this->_M_format(__t, index_sequence_for<_Tps...>(), __fc); } + }; + + // [format.range.formatter], class template range_formatter + template<typename _Tp, __format::__char _CharT> + requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT> + class range_formatter + { + using _String_view = basic_string_view<_CharT>; + using _Seps = __format::_Separators<_CharT>; + + public: + constexpr void + set_separator(basic_string_view<_CharT> __sep) noexcept + { _M_sep = __sep; } + + constexpr void + set_brackets(basic_string_view<_CharT> __open, + basic_string_view<_CharT> __close) noexcept + { + _M_open = __open; + _M_close = __close; + } + + constexpr formatter<_Tp, _CharT>& + underlying() noexcept + { return _M_fval; } + + constexpr const formatter<_Tp, _CharT>& + underlying() const noexcept + { return _M_fval; } + + // We deviate from standard, that declares this as template accepting + // unconstrained ParseContext type, which seems unimplementable. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { + auto __first = __pc.begin(); + const auto __last = __pc.end(); + __format::_Spec<_CharT> __spec{}; + bool __no_brace = false; + + auto __finished = [&] + { return __first == __last || *__first == '}'; }; + + auto __finalize = [&] + { + _M_spec = __spec; + return __first; + }; + + auto __parse_val = [&](_String_view __nfs = _String_view()) + { + basic_format_parse_context<_CharT> __npc(__nfs); + if (_M_fval.parse(__npc) != __npc.end()) + __format::__failed_to_parse_format_spec(); + if constexpr (__format::__has_debug_format<formatter<_Tp, _CharT>>) + _M_fval.set_debug_format(); + return __finalize(); + }; + + if (__finished()) + return __parse_val(); + + __first = __spec._M_parse_fill_and_align(__first, __last, "{:"); + if (__finished()) + return __parse_val(); + + __first = __spec._M_parse_width(__first, __last, __pc); + if (__finished()) + return __parse_val(); + + if (*__first == '?') + { + ++__first; + __spec._M_debug = true; + if (__finished() || *__first != 's') + __throw_format_error("format error: '?' is allowed only in" + " combination with 's'"); + } + + if (*__first == 's') + { + ++__first; + if constexpr (same_as<_Tp, _CharT>) + { + __spec._M_type = __format::_Pres_s; + if (__finished()) + return __finalize(); + __throw_format_error("format error: element format specifier" + " cannot be provided when 's' specifier is used"); + } + else + __throw_format_error("format error: 's' specifier requires" + " range of character types"); + } + + if (__finished()) + return __parse_val(); + + if (*__first == 'n') + { + ++__first; + _M_open = _M_close = _String_view(); + __no_brace = true; + } + + if (__finished()) + return __parse_val(); + + if (*__first == 'm') + { + _String_view __m(__first, 1); + ++__first; + if constexpr (__format::__is_map_formattable<_Tp>) + { + _M_sep = _Seps::_S_comma(); + if (!__no_brace) + { + _M_open = _Seps::_S_braces().substr(0, 1); + _M_close = _Seps::_S_braces().substr(1, 1); + } + if (__finished()) + return __parse_val(__m); + __throw_format_error("format error: element format specifier" + " cannot be provided when 'm' specifier is used"); + } + else + __throw_format_error("format error: 'm' specifier requires" + " range of pairs or tuples of two elements"); + } + + if (__finished()) + return __parse_val(); + + if (*__first == ':') + { + __pc.advance_to(++__first); + __first = _M_fval.parse(__pc); + } + + if (__finished()) + return __finalize(); + + __format::__failed_to_parse_format_spec(); + } + + // We deviate from standard, that declares this as template accepting + // unconstrained FormatContext type, which seems unimplementable. + template<ranges::input_range _Rg, typename _Out> + requires formattable<ranges::range_reference_t<_Rg>, _CharT> && + same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, _Tp> + typename basic_format_context<_Out, _CharT>::iterator + format(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const + { + using _Range = remove_reference_t<_Rg>; + if constexpr (__format::__simply_formattable_range<_Range, _CharT>) + return _M_format<const _Range>(__rg, __fc); + else + return _M_format(__rg, __fc); + } + + private: + template<ranges::input_range _Rg, typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc) const + { + if constexpr (same_as<_Tp, _CharT>) + if (_M_spec._M_type == __format::_Pres_s) + { + __format::__formatter_str __fstr(_M_spec); + return __fstr._M_format_range(__rg, __fc); + } + return __format::__format_padded( + __fc, _M_spec, + [this, &__rg](basic_format_context<_Out, _CharT>& __nfc) + { return _M_format_elems(__rg, __nfc); }); + } + + + template<ranges::input_range _Rg, typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + _M_format_elems(_Rg& __rg, + basic_format_context<_Out, _CharT>& __fc) const + { + auto __out = __format::__write(__fc.out(), _M_open); + + auto __first = ranges::begin(__rg); + auto const __last = ranges::end(__rg); + if (__first == __last) + return __format::__write(__out, _M_close); + + __fc.advance_to(__out); + __out = _M_fval.format(*__first, __fc); + for (++__first; __first != __last; ++__first) + { + __out = __format::__write(__out, _M_sep); + __fc.advance_to(__out); + __out = _M_fval.format(*__first, __fc); + } + + return __format::__write(__out, _M_close); + } + + __format::_Spec<_CharT> _M_spec{}; + _String_view _M_open = _Seps::_S_squares().substr(0, 1); + _String_view _M_close = _Seps::_S_squares().substr(1, 1); + _String_view _M_sep = _Seps::_S_comma(); + formatter<_Tp, _CharT> _M_fval; + }; + + // In standard this is shown as inheriting from specialization of + // exposition only specialization for range-default-formatter for + // each range_format. We opt for simpler implementation. // [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr], // specializations for maps, sets, and strings - template<ranges::input_range _Rg, typename _CharT> + template<ranges::input_range _Rg, __format::__char _CharT> requires (format_kind<_Rg> != range_format::disabled) && formattable<ranges::range_reference_t<_Rg>, _CharT> struct formatter<_Rg, _CharT> - : __format::__range_default_formatter<format_kind<_Rg>, _Rg, _CharT> - { }; + { + private: + static const bool _S_range_format_is_string = + (format_kind<_Rg> == range_format::string) + || (format_kind<_Rg> == range_format::debug_string); + using _Vt = remove_cvref_t< + ranges::range_reference_t< + __format::__maybe_const_range<_Rg, _CharT>>>; + + static consteval bool _S_is_correct() + { + if constexpr (_S_range_format_is_string) + static_assert(same_as<_Vt, _CharT>); + return true; + } + + static_assert(_S_is_correct()); + + public: + constexpr formatter() noexcept + { + using _Seps = __format::_Separators<_CharT>; + if constexpr (format_kind<_Rg> == range_format::map) + { + static_assert(__format::__is_map_formattable<_Vt>); + _M_under.set_brackets(_Seps::_S_braces().substr(0, 1), + _Seps::_S_braces().substr(1, 1)); + _M_under.underlying().set_brackets({}, {}); + _M_under.underlying().set_separator(_Seps::_S_colon()); + } + else if constexpr (format_kind<_Rg> == range_format::set) + _M_under.set_brackets(_Seps::_S_braces().substr(0, 1), + _Seps::_S_braces().substr(1, 1)); + } + + constexpr void + set_separator(basic_string_view<_CharT> __sep) noexcept + requires (!_S_range_format_is_string) + { _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) + { _M_under.set_brackets(__open, __close); } + + // We deviate from standard, that declares this as template accepting + // unconstrained ParseContext type, which seems unimplementable. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { + auto __res = _M_under.parse(__pc); + if constexpr (format_kind<_Rg> == range_format::debug_string) + _M_under.set_debug_format(); + return __res; + } + + // We deviate from standard, that declares this as template accepting + // unconstrained FormatContext type, which seems unimplementable. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__format::__maybe_const_range<_Rg, _CharT>& __rg, + basic_format_context<_Out, _CharT>& __fc) const + { + if constexpr (_S_range_format_is_string) + return _M_under._M_format_range(__rg, __fc); + else + return _M_under.format(__rg, __fc); + } + + private: + using _Formatter_under + = __conditional_t<_S_range_format_is_string, + __format::__formatter_str<_CharT>, + range_formatter<_Vt, _CharT>>; + _Formatter_under _M_under; + }; #endif // C++23 formatting ranges +#undef _GLIBCXX_WIDEN _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/std/forward_list b/libstdc++-v3/include/std/forward_list index 166fdb0..d478851 100644 --- a/libstdc++-v3/include/std/forward_list +++ b/libstdc++-v3/include/std/forward_list @@ -49,6 +49,7 @@ #define __glibcxx_want_algorithm_default_value_type #define __glibcxx_want_allocator_traits_is_always_equal +#define __glibcxx_want_containers_ranges #define __glibcxx_want_erase_if #define __glibcxx_want_incomplete_container_elements #define __glibcxx_want_list_remove_return_type diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 1077e96..307bcb9 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -52,6 +52,21 @@ #if __cplusplus >= 201103L +#define __glibcxx_want_boyer_moore_searcher +#define __glibcxx_want_bind_front +#define __glibcxx_want_bind_back +#define __glibcxx_want_constexpr_functional +#define __glibcxx_want_copyable_function +#define __glibcxx_want_function_ref +#define __glibcxx_want_invoke +#define __glibcxx_want_invoke_r +#define __glibcxx_want_move_only_function +#define __glibcxx_want_not_fn +#define __glibcxx_want_ranges +#define __glibcxx_want_reference_wrapper +#define __glibcxx_want_transparent_operators +#include <bits/version.h> + #include <tuple> #include <type_traits> #include <bits/functional_hash.h> @@ -72,23 +87,10 @@ # include <bits/ranges_cmp.h> // std::identity, ranges::equal_to etc. # include <compare> #endif -#if __cplusplus > 202002L && _GLIBCXX_HOSTED -# include <bits/move_only_function.h> +#if __glibcxx_move_only_function || __glibcxx_copyable_function || __glibcxx_function_ref +# include <bits/funcwrap.h> #endif -#define __glibcxx_want_boyer_moore_searcher -#define __glibcxx_want_bind_front -#define __glibcxx_want_bind_back -#define __glibcxx_want_constexpr_functional -#define __glibcxx_want_invoke -#define __glibcxx_want_invoke_r -#define __glibcxx_want_move_only_function -#define __glibcxx_want_not_fn -#define __glibcxx_want_ranges -#define __glibcxx_want_reference_wrapper -#define __glibcxx_want_transparent_operators -#include <bits/version.h> - #endif // C++11 namespace std _GLIBCXX_VISIBILITY(default) diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index b7ab233..0806900 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -1486,12 +1486,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)> final : __future_base::_Task_state_base<_Res(_Args...)> { +#ifdef __cpp_lib_is_invocable // C++ >= 17 + static_assert(is_invocable_r_v<_Res, _Fn&, _Args...>); +#else + static_assert(__is_invocable<_Fn&, _Args...>::value, + "_Fn& is invocable with _Args..."); +#endif + template<typename _Fn2> _Task_state(_Fn2&& __fn, const _Alloc& __a) : _Task_state_base<_Res(_Args...)>(__a), _M_impl(std::forward<_Fn2>(__fn), __a) { } + template<typename _Fn2> + static shared_ptr<_Task_state_base<_Res(_Args...)>> + _S_create(_Fn2&& __fn, const _Alloc& __a) + { + return std::allocate_shared<_Task_state>(__a, + std::forward<_Fn2>(__fn), + __a); + } + private: virtual void _M_run(_Args&&... __args) @@ -1515,7 +1531,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } virtual shared_ptr<_Task_state_base<_Res(_Args...)>> - _M_reset(); + _M_reset() + { return _S_create(std::move(_M_impl._M_fn), _M_impl); } struct _Impl : _Alloc { @@ -1525,38 +1542,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Fn _M_fn; } _M_impl; }; - - template<typename _Signature, typename _Fn, - typename _Alloc = std::allocator<int>> - shared_ptr<__future_base::_Task_state_base<_Signature>> - __create_task_state(_Fn&& __fn, const _Alloc& __a = _Alloc()) - { - typedef typename decay<_Fn>::type _Fn2; - typedef __future_base::_Task_state<_Fn2, _Alloc, _Signature> _State; - return std::allocate_shared<_State>(__a, std::forward<_Fn>(__fn), __a); - } - - template<typename _Fn, typename _Alloc, typename _Res, typename... _Args> - shared_ptr<__future_base::_Task_state_base<_Res(_Args...)>> - __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)>::_M_reset() - { - return __create_task_state<_Res(_Args...)>(std::move(_M_impl._M_fn), - static_cast<_Alloc&>(_M_impl)); - } /// @endcond /// packaged_task template<typename _Res, typename... _ArgTypes> class packaged_task<_Res(_ArgTypes...)> { - typedef __future_base::_Task_state_base<_Res(_ArgTypes...)> _State_type; + using _State_type = __future_base::_Task_state_base<_Res(_ArgTypes...)>; shared_ptr<_State_type> _M_state; // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3039. Unnecessary decay in thread and packaged_task template<typename _Fn, typename _Fn2 = __remove_cvref_t<_Fn>> - using __not_same - = typename enable_if<!is_same<packaged_task, _Fn2>::value>::type; + using __not_same = __enable_if_t<!is_same<packaged_task, _Fn2>::value>; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4154. The Mandates for std::packaged_task's constructor + // from a callable entity should consider decaying. + template<typename _Fn, typename _Alloc = std::allocator<int>> + using _Task_state + = __future_base::_Task_state<__decay_t<_Fn>, _Alloc, + _Res(_ArgTypes...)>; public: // Construction and destruction @@ -1565,16 +1571,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Fn, typename = __not_same<_Fn>> explicit packaged_task(_Fn&& __fn) - : _M_state( - __create_task_state<_Res(_ArgTypes...)>(std::forward<_Fn>(__fn))) - { -#ifdef __cpp_lib_is_invocable // C++ >= 17 - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 4154. The Mandates for std::packaged_task's constructor - // from a callable entity should consider decaying - static_assert(is_invocable_r_v<_Res, decay_t<_Fn>&, _ArgTypes...>); -#endif - } + : _M_state(_Task_state<_Fn>::_S_create(std::forward<_Fn>(__fn), {})) + { } #if __cplusplus < 201703L // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -1583,8 +1581,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 2921. packaged_task and type-erased allocators template<typename _Fn, typename _Alloc, typename = __not_same<_Fn>> packaged_task(allocator_arg_t, const _Alloc& __a, _Fn&& __fn) - : _M_state(__create_task_state<_Res(_ArgTypes...)>( - std::forward<_Fn>(__fn), __a)) + : _M_state(_Task_state<_Fn, _Alloc>::_S_create(std::forward<_Fn>(__fn), + __a)) { } // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/include/std/generator b/libstdc++-v3/include/std/generator index 3f781f1..7ab2c9e 100644 --- a/libstdc++-v3/include/std/generator +++ b/libstdc++-v3/include/std/generator @@ -153,6 +153,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept { return _Recursive_awaiter { std::move(__r.range) }; } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3899. co_yielding elements of an lvalue generator is + // unnecessarily inefficient + template<typename _R2, typename _V2, typename _A2, typename _U2> + requires std::same_as<_Yield2_t<_R2, _V2>, _Yielded> + auto + yield_value(ranges::elements_of<generator<_R2, _V2, _A2>&, _U2> __r) + noexcept + { return _Recursive_awaiter { std::move(__r.range) }; } + template<ranges::input_range _R, typename _Alloc> requires convertible_to<ranges::range_reference_t<_R>, _Yielded> auto diff --git a/libstdc++-v3/include/std/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/list b/libstdc++-v3/include/std/list index 170499d..2ba0599 100644 --- a/libstdc++-v3/include/std/list +++ b/libstdc++-v3/include/std/list @@ -73,6 +73,7 @@ #define __glibcxx_want_algorithm_default_value_type #define __glibcxx_want_allocator_traits_is_always_equal +#define __glibcxx_want_containers_ranges #define __glibcxx_want_erase_if #define __glibcxx_want_incomplete_container_elements #define __glibcxx_want_list_remove_return_type diff --git a/libstdc++-v3/include/std/map b/libstdc++-v3/include/std/map index 16a397f..6bfb538 100644 --- a/libstdc++-v3/include/std/map +++ b/libstdc++-v3/include/std/map @@ -72,6 +72,7 @@ #endif #define __glibcxx_want_allocator_traits_is_always_equal +#define __glibcxx_want_containers_ranges #define __glibcxx_want_erase_if #define __glibcxx_want_generic_associative_lookup #define __glibcxx_want_map_try_emplace diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan new file mode 100644 index 0000000..c72a640 --- /dev/null +++ b/libstdc++-v3/include/std/mdspan @@ -0,0 +1,1041 @@ +// <mdspan> -*- C++ -*- + +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file mdspan + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_MDSPAN +#define _GLIBCXX_MDSPAN 1 + +#ifdef _GLIBCXX_SYSHDR +#pragma GCC system_header +#endif + +#include <span> +#include <array> +#include <type_traits> +#include <limits> +#include <utility> + +#define __glibcxx_want_mdspan +#include <bits/version.h> + +#ifdef __glibcxx_mdspan + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + namespace __mdspan + { + template<typename _IndexType, array _Extents> + class _ExtentsStorage + { + public: + static consteval bool + _S_is_dyn(size_t __ext) noexcept + { return __ext == dynamic_extent; } + + template<typename _OIndexType> + static constexpr _IndexType + _S_int_cast(const _OIndexType& __other) noexcept + { return _IndexType(__other); } + + static constexpr size_t _S_rank = _Extents.size(); + + // For __r in [0, _S_rank], _S_dynamic_index[__r] is the number + // of dynamic extents up to (and not including) __r. + // + // If __r is the index of a dynamic extent, then + // _S_dynamic_index[__r] is the index of that extent in + // _M_dyn_exts. + static constexpr auto _S_dynamic_index = [] consteval + { + array<size_t, _S_rank+1> __ret; + size_t __dyn = 0; + for (size_t __i = 0; __i < _S_rank; ++__i) + { + __ret[__i] = __dyn; + __dyn += _S_is_dyn(_Extents[__i]); + } + __ret[_S_rank] = __dyn; + return __ret; + }(); + + static constexpr size_t _S_rank_dynamic = _S_dynamic_index[_S_rank]; + + // For __r in [0, _S_rank_dynamic), _S_dynamic_index_inv[__r] is the + // index of the __r-th dynamic extent in _Extents. + static constexpr auto _S_dynamic_index_inv = [] consteval + { + array<size_t, _S_rank_dynamic> __ret; + for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i) + if (_S_is_dyn(_Extents[__i])) + __ret[__r++] = __i; + return __ret; + }(); + + static constexpr size_t + _S_static_extent(size_t __r) noexcept + { return _Extents[__r]; } + + constexpr _IndexType + _M_extent(size_t __r) const noexcept + { + auto __se = _Extents[__r]; + if (__se == dynamic_extent) + return _M_dyn_exts[_S_dynamic_index[__r]]; + else + return __se; + } + + template<size_t _OtherRank, typename _GetOtherExtent> + constexpr void + _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept + { + for (size_t __i = 0; __i < _S_rank_dynamic; ++__i) + { + size_t __di = __i; + if constexpr (_OtherRank != _S_rank_dynamic) + __di = _S_dynamic_index_inv[__i]; + _M_dyn_exts[__i] = _S_int_cast(__get_extent(__di)); + } + } + + constexpr + _ExtentsStorage() noexcept = default; + + template<typename _OIndexType, array _OExtents> + constexpr + _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>& + __other) noexcept + { + _M_init_dynamic_extents<_S_rank>([&__other](size_t __i) + { return __other._M_extent(__i); }); + } + + template<typename _OIndexType, size_t _Nm> + constexpr + _ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept + { + _M_init_dynamic_extents<_Nm>( + [&__exts](size_t __i) -> const _OIndexType& + { return __exts[__i]; }); + } + + static constexpr span<const size_t> + _S_static_extents(size_t __begin, size_t __end) noexcept + { + return {_Extents.data() + __begin, _Extents.data() + __end}; + } + + constexpr span<const _IndexType> + _M_dynamic_extents(size_t __begin, size_t __end) const noexcept + requires (_Extents.size() > 0) + { + return {_M_dyn_exts + _S_dynamic_index[__begin], + _M_dyn_exts + _S_dynamic_index[__end]}; + } + + private: + using _S_storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type; + [[no_unique_address]] _S_storage _M_dyn_exts{}; + }; + + template<typename _OIndexType, typename _SIndexType> + concept __valid_index_type = + is_convertible_v<_OIndexType, _SIndexType> && + is_nothrow_constructible_v<_SIndexType, _OIndexType>; + + template<size_t _Extent, typename _IndexType> + concept + __valid_static_extent = _Extent == dynamic_extent + || _Extent <= numeric_limits<_IndexType>::max(); + } + + namespace __mdspan + { + template<typename _Extents> + constexpr span<const size_t> + __static_extents(size_t __begin = 0, size_t __end = _Extents::rank()) + noexcept + { return _Extents::_S_storage::_S_static_extents(__begin, __end); } + + template<typename _Extents> + constexpr span<const typename _Extents::index_type> + __dynamic_extents(const _Extents& __exts, size_t __begin = 0, + size_t __end = _Extents::rank()) noexcept + { + return __exts._M_exts._M_dynamic_extents(__begin, __end); + } + } + + template<typename _IndexType, size_t... _Extents> + class extents + { + static_assert(__is_standard_integer<_IndexType>::value, + "IndexType must be a signed or unsigned integer type"); + static_assert( + (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...), + "Extents must either be dynamic or representable as IndexType"); + + public: + using index_type = _IndexType; + using size_type = make_unsigned_t<index_type>; + using rank_type = size_t; + + static constexpr rank_type + rank() noexcept { return _S_storage::_S_rank; } + + static constexpr rank_type + rank_dynamic() noexcept { return _S_storage::_S_rank_dynamic; } + + static constexpr size_t + static_extent(rank_type __r) noexcept + { + __glibcxx_assert(__r < rank()); + if constexpr (rank() == 0) + __builtin_trap(); + else + return _S_storage::_S_static_extent(__r); + } + + constexpr index_type + extent(rank_type __r) const noexcept + { + __glibcxx_assert(__r < rank()); + if constexpr (rank() == 0) + __builtin_trap(); + else + return _M_exts._M_extent(__r); + } + + constexpr + extents() noexcept = default; + + private: + static consteval bool + _S_is_less_dynamic(size_t __ext, size_t __oext) + { return (__ext != dynamic_extent) && (__oext == dynamic_extent); } + + template<typename _OIndexType, size_t... _OExtents> + static consteval bool + _S_ctor_explicit() + { + return (_S_is_less_dynamic(_Extents, _OExtents) || ...) + || (numeric_limits<index_type>::max() + < numeric_limits<_OIndexType>::max()); + } + + template<size_t... _OExtents> + static consteval bool + _S_is_compatible_extents() + { + if constexpr (sizeof...(_OExtents) != rank()) + return false; + else + return ((_OExtents == dynamic_extent || _Extents == dynamic_extent + || _OExtents == _Extents) && ...); + } + + public: + template<typename _OIndexType, size_t... _OExtents> + requires (_S_is_compatible_extents<_OExtents...>()) + constexpr explicit(_S_ctor_explicit<_OIndexType, _OExtents...>()) + extents(const extents<_OIndexType, _OExtents...>& __other) noexcept + : _M_exts(__other._M_exts) + { } + + template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> + requires (sizeof...(_OIndexTypes) == rank() + || sizeof...(_OIndexTypes) == rank_dynamic()) + constexpr explicit extents(_OIndexTypes... __exts) noexcept + : _M_exts(span<const _IndexType, sizeof...(_OIndexTypes)>( + initializer_list{_S_storage::_S_int_cast(__exts)...})) + { } + + template<__mdspan::__valid_index_type<index_type> _OIndexType, size_t _Nm> + requires (_Nm == rank() || _Nm == rank_dynamic()) + constexpr explicit(_Nm != rank_dynamic()) + extents(span<_OIndexType, _Nm> __exts) noexcept + : _M_exts(span<const _OIndexType, _Nm>(__exts)) + { } + + template<__mdspan::__valid_index_type<index_type> _OIndexType, size_t _Nm> + requires (_Nm == rank() || _Nm == rank_dynamic()) + constexpr explicit(_Nm != rank_dynamic()) + extents(const array<_OIndexType, _Nm>& __exts) noexcept + : _M_exts(span<const _OIndexType, _Nm>(__exts)) + { } + + template<typename _OIndexType, size_t... _OExtents> + friend constexpr bool + operator==(const extents& __self, + const extents<_OIndexType, _OExtents...>& __other) noexcept + { + if constexpr (!_S_is_compatible_extents<_OExtents...>()) + return false; + else + { + for (size_t __i = 0; __i < __self.rank(); ++__i) + if (!cmp_equal(__self.extent(__i), __other.extent(__i))) + return false; + return true; + } + } + + private: + friend span<const size_t> + __mdspan::__static_extents<extents>(size_t, size_t); + + friend span<const index_type> + __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t); + + using _S_storage = __mdspan::_ExtentsStorage< + _IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>; + [[no_unique_address]] _S_storage _M_exts; + + template<typename _OIndexType, size_t... _OExtents> + friend class extents; + }; + + namespace __mdspan + { + template<typename _Tp, size_t _Nm> + constexpr bool + __contains_zero(span<_Tp, _Nm> __exts) noexcept + { + for (size_t __i = 0; __i < __exts.size(); ++__i) + if (__exts[__i] == 0) + return true; + return false; + } + + template<typename _Extents> + constexpr bool + __empty(const _Extents& __exts) noexcept + { + if constexpr (__contains_zero(__static_extents<_Extents>())) + return true; + else if constexpr (_Extents::rank_dynamic() > 0) + return __contains_zero(__dynamic_extents(__exts)); + else + return false; + } + + constexpr size_t + __static_extents_prod(const auto& __sta_exts) noexcept + { + size_t __ret = 1; + for (auto __factor : __sta_exts) + if (__factor != dynamic_extent) + __ret *= __factor; + return __ret; + } + + template<typename _Extents> + constexpr typename _Extents::index_type + __exts_prod(const _Extents& __exts, size_t __begin, size_t __end) noexcept + { + using _IndexType = typename _Extents::index_type; + + size_t __ret = 1; + if constexpr (_Extents::rank_dynamic() != _Extents::rank()) + { + auto __sta_exts = __static_extents<_Extents>(__begin, __end); + __ret = __static_extents_prod(__sta_exts); + if (__ret == 0) + return 0; + } + + if constexpr (_Extents::rank_dynamic() > 0) + for (auto __factor : __dynamic_extents(__exts, __begin, __end)) + __ret *= size_t(__factor); + return _IndexType(__ret); + } + + template<typename _Extents> + constexpr typename _Extents::index_type + __fwd_prod(const _Extents& __exts, size_t __r) noexcept + { return __exts_prod(__exts, 0, __r); } + + template<typename _Extents> + constexpr typename _Extents::index_type + __rev_prod(const _Extents& __exts, size_t __r) noexcept + { return __exts_prod(__exts, __r + 1, __exts.rank()); } + + template<typename _IndexType, size_t... _Counts> + auto __build_dextents_type(integer_sequence<size_t, _Counts...>) + -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>; + + template<typename _Tp> + consteval size_t + __dynamic_extent() { return dynamic_extent; } + } + + template<typename _IndexType, size_t _Rank> + using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>( + make_index_sequence<_Rank>())); + + template<typename... _Integrals> + requires (is_convertible_v<_Integrals, size_t> && ...) + explicit extents(_Integrals...) -> + extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>; + + struct layout_left + { + template<typename _Extents> + class mapping; + }; + + struct layout_right + { + template<typename _Extents> + class mapping; + }; + + struct layout_stride + { + template<typename _Extents> + class mapping; + }; + + namespace __mdspan + { + template<typename _Tp> + constexpr bool __is_extents = false; + + template<typename _IndexType, size_t... _Extents> + constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true; + + template<typename _Extents, typename... _Indices> + constexpr typename _Extents::index_type + __linear_index_left(const _Extents& __exts, _Indices... __indices) + noexcept + { + using _IndexType = typename _Extents::index_type; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + _IndexType __mult = 1; + auto __update = [&, __pos = 0u](_IndexType __idx) mutable + { + __res += __idx * __mult; + __mult *= __exts.extent(__pos); + ++__pos; + }; + (__update(__indices), ...); + } + return __res; + } + + template<typename _Extents, + typename _IndexType = typename _Extents::index_type> + consteval _IndexType + __static_quotient(_IndexType __nom = numeric_limits<_IndexType>::max()) + { + auto __sta_exts = __static_extents<_Extents>(); + for (auto __factor : __sta_exts) + { + if (__factor != dynamic_extent) + __nom /= _IndexType(__factor); + if (__nom == 0) + break; + } + return __nom; + } + + template<typename _Extents> + constexpr bool + __is_representable_extents(const _Extents& __exts) noexcept + { + using _IndexType = _Extents::index_type; + + if constexpr (__contains_zero(__static_extents<_Extents>())) + return true; + else + { + constexpr auto __sta_quo = __static_quotient<_Extents>(); + if constexpr (_Extents::rank_dynamic() == 0) + return __sta_quo != 0; + else + { + auto __dyn_exts = __dynamic_extents(__exts); + if (__contains_zero(__dyn_exts)) + return true; + + if constexpr (__sta_quo == 0) + return false; + else + { + auto __dyn_quo = _IndexType(__sta_quo); + for (auto __factor : __dyn_exts) + { + __dyn_quo /= __factor; + if (__dyn_quo == 0) + return false; + } + return true; + } + } + } + } + + template<typename _Extents, typename _IndexType> + concept __representable_size = _Extents::rank_dynamic() != 0 + || __contains_zero(__static_extents<_Extents>()) + || (__static_quotient<_Extents, _IndexType>() != 0); + + template<typename _Layout, typename _Mapping> + concept __mapping_of = + is_same_v<typename _Layout::mapping<typename _Mapping::extents_type>, + _Mapping>; + + template<typename _Mapping> + concept __standardized_mapping = __mapping_of<layout_left, _Mapping> + || __mapping_of<layout_right, _Mapping> + || __mapping_of<layout_stride, _Mapping>; + + // A tag type to create internal ctors. + class __internal_ctor + { }; + } + + template<typename _Extents> + class layout_left::mapping + { + public: + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_left; + + static_assert(__mdspan::__representable_size<extents_type, index_type>, + "The size of extents_type must be representable as index_type"); + + constexpr + mapping() noexcept = default; + + constexpr + mapping(const mapping&) noexcept = default; + + constexpr + mapping(const extents_type& __extents) noexcept + : _M_extents(__extents) + { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + template<typename _OExtents> + requires (extents_type::rank() <= 1) + && is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const layout_right::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + // noexcept for consistency with other layouts. + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { __glibcxx_assert(*this == __other); } + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_extents; } + + constexpr index_type + required_span_size() const noexcept + { return __mdspan::__fwd_prod(_M_extents, extents_type::rank()); } + + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == extents_type::rank()) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_left(_M_extents, + static_cast<index_type>(__indices)...); + } + + static constexpr bool + is_always_unique() noexcept { return true; } + + static constexpr bool + is_always_exhaustive() noexcept { return true; } + + static constexpr bool + is_always_strided() noexcept { return true; } + + static constexpr bool + is_unique() noexcept { return true; } + + static constexpr bool + is_exhaustive() noexcept { return true; } + + static constexpr bool + is_strided() noexcept { return true; } + + constexpr index_type + stride(rank_type __i) const noexcept + requires (extents_type::rank() > 0) + { + __glibcxx_assert(__i < extents_type::rank()); + return __mdspan::__fwd_prod(_M_extents, __i); + } + + template<typename _OExtents> + requires (extents_type::rank() == _OExtents::rank()) + friend constexpr bool + operator==(const mapping& __self, const mapping<_OExtents>& __other) + noexcept + { return __self.extents() == __other.extents(); } + + private: + template<typename _OExtents> + constexpr explicit + mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept + : _M_extents(__oexts) + { + static_assert(__mdspan::__representable_size<_OExtents, index_type>, + "The size of OtherExtents must be representable as index_type"); + __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); + } + + [[no_unique_address]] extents_type _M_extents{}; + }; + + namespace __mdspan + { + template<typename _Extents, typename... _Indices> + constexpr typename _Extents::index_type + __linear_index_right(const _Extents& __exts, _Indices... __indices) + noexcept + { + using _IndexType = typename _Extents::index_type; + array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...}; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + _IndexType __mult = 1; + auto __update = [&, __pos = __exts.rank()](_IndexType) mutable + { + --__pos; + __res += __ind_arr[__pos] * __mult; + __mult *= __exts.extent(__pos); + }; + (__update(__indices), ...); + } + return __res; + } + } + + template<typename _Extents> + class layout_right::mapping + { + public: + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_right; + + static_assert(__mdspan::__representable_size<extents_type, index_type>, + "The size of extents_type must be representable as index_type"); + + constexpr + mapping() noexcept = default; + + constexpr + mapping(const mapping&) noexcept = default; + + constexpr + mapping(const extents_type& __extents) noexcept + : _M_extents(__extents) + { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + template<typename _OExtents> + requires (extents_type::rank() <= 1) + && is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const layout_left::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { __glibcxx_assert(*this == __other); } + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_extents; } + + constexpr index_type + required_span_size() const noexcept + { return __mdspan::__fwd_prod(_M_extents, extents_type::rank()); } + + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == extents_type::rank()) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_right( + _M_extents, static_cast<index_type>(__indices)...); + } + + static constexpr bool + is_always_unique() noexcept + { return true; } + + static constexpr bool + is_always_exhaustive() noexcept + { return true; } + + static constexpr bool + is_always_strided() noexcept + { return true; } + + static constexpr bool + is_unique() noexcept + { return true; } + + static constexpr bool + is_exhaustive() noexcept + { return true; } + + static constexpr bool + is_strided() noexcept + { return true; } + + constexpr index_type + stride(rank_type __i) const noexcept + requires (extents_type::rank() > 0) + { + __glibcxx_assert(__i < extents_type::rank()); + return __mdspan::__rev_prod(_M_extents, __i); + } + + template<typename _OExtents> + requires (extents_type::rank() == _OExtents::rank()) + friend constexpr bool + operator==(const mapping& __self, const mapping<_OExtents>& __other) + noexcept + { return __self.extents() == __other.extents(); } + + private: + template<typename _OExtents> + constexpr explicit + mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept + : _M_extents(__oexts) + { + static_assert(__mdspan::__representable_size<_OExtents, index_type>, + "The size of OtherExtents must be representable as index_type"); + __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); + } + + [[no_unique_address]] extents_type _M_extents{}; + }; + + namespace __mdspan + { + template<typename _Mp> + concept __mapping_alike = requires + { + requires __is_extents<typename _Mp::extents_type>; + { _Mp::is_always_strided() } -> same_as<bool>; + { _Mp::is_always_exhaustive() } -> same_as<bool>; + { _Mp::is_always_unique() } -> same_as<bool>; + bool_constant<_Mp::is_always_strided()>::value; + bool_constant<_Mp::is_always_exhaustive()>::value; + bool_constant<_Mp::is_always_unique()>::value; + }; + + template<typename _Mapping> + constexpr typename _Mapping::index_type + __offset(const _Mapping& __m) noexcept + { + using _IndexType = typename _Mapping::index_type; + constexpr auto __rank = _Mapping::extents_type::rank(); + + if constexpr (__standardized_mapping<_Mapping>) + return 0; + else if (__empty(__m.extents())) + return 0; + else + { + auto __impl = [&__m]<size_t... _Counts>(index_sequence<_Counts...>) + { return __m(((void) _Counts, _IndexType(0))...); }; + return __impl(make_index_sequence<__rank>()); + } + } + + template<typename _Mapping, typename... _Indices> + constexpr typename _Mapping::index_type + __linear_index_strides(const _Mapping& __m, _Indices... __indices) + noexcept + { + using _IndexType = typename _Mapping::index_type; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + auto __update = [&, __pos = 0u](_IndexType __idx) mutable + { + __res += __idx * __m.stride(__pos++); + }; + (__update(__indices), ...); + } + return __res; + } + } + + template<typename _Extents> + class layout_stride::mapping + { + public: + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_stride; + + static_assert(__mdspan::__representable_size<extents_type, index_type>, + "The size of extents_type must be representable as index_type"); + + constexpr + mapping() noexcept + { + // The precondition is either statically asserted, or automatically + // satisfied because dynamic extents are zero-initialized. + size_t __stride = 1; + for (size_t __i = extents_type::rank(); __i > 0; --__i) + { + _M_strides[__i - 1] = index_type(__stride); + __stride *= size_t(_M_extents.extent(__i - 1)); + } + } + + constexpr + mapping(const mapping&) noexcept = default; + + template<__mdspan::__valid_index_type<index_type> _OIndexType> + constexpr + mapping(const extents_type& __exts, + span<_OIndexType, extents_type::rank()> __strides) noexcept + : _M_extents(__exts) + { + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + _M_strides[__i] = index_type(as_const(__strides[__i])); + } + + template<__mdspan::__valid_index_type<index_type> _OIndexType> + constexpr + mapping(const extents_type& __exts, + const array<_OIndexType, extents_type::rank()>& __strides) + noexcept + : mapping(__exts, + span<const _OIndexType, extents_type::rank()>(__strides)) + { } + + template<__mdspan::__mapping_alike _StridedMapping> + requires (is_constructible_v<extents_type, + typename _StridedMapping::extents_type> + && _StridedMapping::is_always_unique() + && _StridedMapping::is_always_strided()) + constexpr explicit(!( + is_convertible_v<typename _StridedMapping::extents_type, extents_type> + && __mdspan::__standardized_mapping<_StridedMapping>)) + mapping(const _StridedMapping& __other) noexcept + : _M_extents(__other.extents()) + { + using _OIndexType = _StridedMapping::index_type; + using _OExtents = _StridedMapping::extents_type; + + __glibcxx_assert(__mdspan::__offset(__other) == 0); + static_assert(__mdspan::__representable_size<_OExtents, index_type>, + "The size of StridedMapping::extents_type must be representable as" + " index_type"); + if constexpr (cmp_greater(numeric_limits<_OIndexType>::max(), + numeric_limits<index_type>::max())) + __glibcxx_assert(!cmp_less(numeric_limits<index_type>::max(), + __other.required_span_size()) + && "other.required_span_size() must be representable" + " as index_type"); + if constexpr (extents_type::rank() > 0) + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + _M_strides[__i] = index_type(__other.stride(__i)); + } + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_extents; } + + constexpr array<index_type, extents_type::rank()> + strides() const noexcept + { + array<index_type, extents_type::rank()> __ret; + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + __ret[__i] = _M_strides[__i]; + return __ret; + } + + constexpr index_type + required_span_size() const noexcept + { + if (__mdspan::__empty(_M_extents)) + return 0; + + index_type __ret = 1; + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + __ret += (_M_extents.extent(__i) - 1) * _M_strides[__i]; + return __ret; + } + + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == extents_type::rank()) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_strides(*this, + static_cast<index_type>(__indices)...); + } + + static constexpr bool + is_always_unique() noexcept { return true; } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4266. layout_stride::mapping should treat empty mappings as exhaustive + static constexpr bool + is_always_exhaustive() noexcept + { + return (_Extents::rank() == 0) || __mdspan::__contains_zero( + __mdspan::__static_extents<extents_type>()); + } + + static constexpr bool + is_always_strided() noexcept { return true; } + + static constexpr bool + is_unique() noexcept { return true; } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4266. layout_stride::mapping should treat empty mappings as exhaustive + constexpr bool + is_exhaustive() const noexcept + { + if constexpr (!is_always_exhaustive()) + { + constexpr auto __rank = extents_type::rank(); + auto __size = __mdspan::__fwd_prod(_M_extents, __rank); + if(__size > 0) + return __size == required_span_size(); + } + return true; + } + + static constexpr bool + is_strided() noexcept { return true; } + + constexpr index_type + stride(rank_type __r) const noexcept { return _M_strides[__r]; } + + template<__mdspan::__mapping_alike _OMapping> + requires ((extents_type::rank() == _OMapping::extents_type::rank()) + && _OMapping::is_always_strided()) + friend constexpr bool + operator==(const mapping& __self, const _OMapping& __other) noexcept + { + if (__self.extents() != __other.extents()) + return false; + if constexpr (extents_type::rank() > 0) + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + if (!cmp_equal(__self.stride(__i), __other.stride(__i))) + return false; + return __mdspan::__offset(__other) == 0; + } + + private: + using _S_strides_t = typename __array_traits<index_type, + extents_type::rank()>::_Type; + [[no_unique_address]] extents_type _M_extents; + [[no_unique_address]] _S_strides_t _M_strides; + }; + + template<typename _ElementType> + struct default_accessor + { + static_assert(!is_array_v<_ElementType>, + "ElementType must not be an array type"); + static_assert(!is_abstract_v<_ElementType>, + "ElementType must not be an abstract class type"); + + using offset_policy = default_accessor; + using element_type = _ElementType; + using reference = element_type&; + using data_handle_type = element_type*; + + constexpr + default_accessor() noexcept = default; + + template<typename _OElementType> + requires is_convertible_v<_OElementType(*)[], element_type(*)[]> + constexpr + default_accessor(default_accessor<_OElementType>) noexcept + { } + + constexpr reference + access(data_handle_type __p, size_t __i) const noexcept + { return __p[__i]; } + + constexpr data_handle_type + offset(data_handle_type __p, size_t __i) const noexcept + { return __p + __i; } + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} +#endif +#endif diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory index 99f542d..1da03b3 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,11 @@ #define __glibcxx_want_constexpr_dynamic_alloc #define __glibcxx_want_constexpr_memory #define __glibcxx_want_enable_shared_from_this +#define __glibcxx_want_indirect #define __glibcxx_want_make_unique #define __glibcxx_want_out_ptr #define __glibcxx_want_parallel_algorithm +#define __glibcxx_want_polymorphic #define __glibcxx_want_ranges #define __glibcxx_want_raw_memory_algorithms #define __glibcxx_want_shared_ptr_arrays diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex index b3f89c0..e575a81 100644 --- a/libstdc++-v3/include/std/mutex +++ b/libstdc++-v3/include/std/mutex @@ -733,7 +733,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } -#ifdef __cpp_lib_scoped_lock // C++ >= 17 && hosted && gthread +#ifdef __cpp_lib_scoped_lock // C++ >= 17 /** @brief A scoped lock type for multiple lockable objects. * * A scoped_lock controls mutex ownership within a scope, releasing diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric index 4d36fcd..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); } @@ -732,12 +732,11 @@ namespace __detail /// @} group numeric_ops #endif // C++17 +#if __glibcxx_ranges_iota >= 202202L // C++ >= 23 namespace ranges { -#if __glibcxx_ranges_iota >= 202202L // C++ >= 23 - template<typename _Out, typename _Tp> - using iota_result = out_value_result<_Out, _Tp>; + using iota_result = out_value_result<_Out, _Tp>; struct __iota_fn { @@ -762,9 +761,8 @@ namespace ranges }; inline constexpr __iota_fn iota{}; - -#endif // __glibcxx_ranges_iota } // namespace ranges +#endif // __glibcxx_ranges_iota _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index a616dc0..cc7af5b 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -36,6 +36,7 @@ #define __glibcxx_want_freestanding_optional #define __glibcxx_want_optional +#define __glibcxx_want_optional_range_support #define __glibcxx_want_constrained_equality #include <bits/version.h> @@ -57,6 +58,11 @@ #if __cplusplus > 202002L # include <concepts> #endif +#ifdef __cpp_lib_optional_range_support // C++ >= 26 +# include <bits/formatfwd.h> +# include <bits/ranges_base.h> +# include <bits/stl_iterator.h> +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -858,6 +864,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: using value_type = _Tp; +#ifdef __cpp_lib_optional_range_support // >= C++26 + using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional>; + using const_iterator = __gnu_cxx::__normal_iterator<const _Tp*, optional>; +#endif constexpr optional() noexcept { } @@ -1158,6 +1168,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } +#ifdef __cpp_lib_optional_range_support // >= C++26 + // Iterator support. + constexpr iterator begin() noexcept + { + return iterator( + this->_M_is_engaged() ? std::addressof(this->_M_get()) : nullptr + ); + } + + constexpr const_iterator begin() const noexcept + { + return const_iterator( + this->_M_is_engaged() ? std::addressof(this->_M_get()) : nullptr + ); + } + + constexpr iterator end() noexcept + { + return begin() + has_value(); + } + + constexpr const_iterator end() const noexcept + { + return begin() + has_value(); + } +#endif // __cpp_lib_optional_range_support + // Observers. constexpr const _Tp* operator->() const noexcept @@ -1772,6 +1809,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Tp> optional(_Tp) -> optional<_Tp>; #endif +#ifdef __cpp_lib_optional_range_support // >= C++26 + template<typename _Tp> + inline constexpr bool + ranges::enable_view<optional<_Tp>> = true; + + template<typename _Tp> + inline constexpr range_format + format_kind<optional<_Tp>> = range_format::disabled; +#endif // __cpp_lib_optional_range_support + #undef _GLIBCXX_USE_CONSTRAINTS_FOR_OPTIONAL _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/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 c06a4c3..9052589 100644 --- a/libstdc++-v3/include/std/queue +++ b/libstdc++-v3/include/std/queue @@ -61,13 +61,88 @@ #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 -#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>. + 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>. + 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 7a339c5..210ac82 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -64,7 +64,6 @@ #define __glibcxx_want_ranges_chunk #define __glibcxx_want_ranges_chunk_by #define __glibcxx_want_ranges_enumerate -#define __glibcxx_want_ranges_iota #define __glibcxx_want_ranges_join_with #define __glibcxx_want_ranges_repeat #define __glibcxx_want_ranges_slide @@ -5337,7 +5336,7 @@ namespace views::__adaptor requires move_constructible<decay_t<_Fp>> && regular_invocable<decay_t<_Fp>&> && is_object_v<decay_t<invoke_result_t<decay_t<_Fp>&>>> constexpr auto - operator() [[nodiscard]] (_Fp&& __f) const + operator() [[nodiscard]] (_Fp&&) const { return views::empty<decay_t<invoke_result_t<decay_t<_Fp>&>>>; } @@ -6599,7 +6598,7 @@ namespace views::__adaptor } friend constexpr difference_type - operator-(default_sentinel_t __y, const _Iterator& __x) + operator-(default_sentinel_t, const _Iterator& __x) requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>> { return __detail::__div_ceil(__x._M_end - __x._M_current, __x._M_n); } @@ -7288,8 +7287,8 @@ namespace views::__adaptor using iterator_category = decltype(_S_iter_cat()); }; - template<bool> struct _Iterator; - template<bool> struct _Sentinel; + template<bool> class _Iterator; + template<bool> class _Sentinel; public: join_with_view() requires (default_initializable<_Vp> @@ -7744,7 +7743,7 @@ namespace views::__adaptor __detail::__box<_Tp> _M_value; [[no_unique_address]] _Bound _M_bound = _Bound(); - struct _Iterator; + class _Iterator; template<typename _Range> friend constexpr auto @@ -8304,7 +8303,7 @@ namespace views::__adaptor } friend constexpr difference_type - operator-(default_sentinel_t __y, const _Iterator& __x) + operator-(default_sentinel_t, const _Iterator& __x) requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>> { return __detail::__div_ceil(__x._M_end - __x._M_current, __x._M_stride); } diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore index bec5ac3..18d0407 100644 --- a/libstdc++-v3/include/std/semaphore +++ b/libstdc++-v3/include/std/semaphore @@ -35,29 +35,28 @@ #include <bits/requires_hosted.h> // concurrency -#if __cplusplus > 201703L -#include <bits/semaphore_base.h> - #define __glibcxx_want_semaphore #include <bits/version.h> -#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && (atomic_wait || posix_sem) +#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && atomic_wait +#include <bits/semaphore_base.h> + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - template<ptrdiff_t __least_max_value = __semaphore_impl::_S_max> + template<ptrdiff_t __least_max_value = _Semaphore_impl<2>::_S_max> class counting_semaphore { static_assert(__least_max_value >= 0); - static_assert(__least_max_value <= __semaphore_impl::_S_max); - __semaphore_impl _M_sem; + _Semaphore_impl<__least_max_value> _M_sem; public: - explicit counting_semaphore(ptrdiff_t __desired) noexcept - : _M_sem(__desired) - { } + constexpr explicit + counting_semaphore(ptrdiff_t __desired) noexcept + : _M_sem(__desired) + { __glibcxx_assert(__desired >= 0 && __desired <= max()); } ~counting_semaphore() = default; @@ -69,8 +68,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __least_max_value; } void - release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1))) - { _M_sem._M_release(__update); } + release(ptrdiff_t __update = 1) noexcept + { + [[maybe_unused]] ptrdiff_t __old = _M_sem._M_release(__update); + __glibcxx_assert(__update >= 0 && __update <= max() - __old); + } void acquire() noexcept(noexcept(_M_sem._M_acquire())) @@ -91,10 +93,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return _M_sem._M_try_acquire_until(__atime); } }; + /** @brief A binary semaphore + * + * @since C++20 + */ using binary_semaphore = std::counting_semaphore<1>; _GLIBCXX_END_NAMESPACE_VERSION } // namespace -#endif // cpp_lib_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE #endif // __cpp_lib_semaphore #endif // _GLIBCXX_SEMAPHORE diff --git a/libstdc++-v3/include/std/set b/libstdc++-v3/include/std/set index 2ebf485..cf7057a 100644 --- a/libstdc++-v3/include/std/set +++ b/libstdc++-v3/include/std/set @@ -72,6 +72,7 @@ #endif #define __glibcxx_want_allocator_traits_is_always_equal +#define __glibcxx_want_containers_ranges #define __glibcxx_want_erase_if #define __glibcxx_want_generic_associative_lookup #define __glibcxx_want_node_extract 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 2f7951a..a57a5a0 100644 --- a/libstdc++-v3/include/std/stack +++ b/libstdc++-v3/include/std/stack @@ -61,10 +61,53 @@ #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 <bits/stl_stack.h> -#define __glibcxx_want_adaptor_iterator_pair_constructor -#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<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..775ec6a 100644 --- a/libstdc++-v3/include/std/stop_token +++ b/libstdc++-v3/include/std/stop_token @@ -34,8 +34,7 @@ #define __glibcxx_want_jthread #include <bits/version.h> -#if __cplusplus > 201703L - +#ifdef __glibcxx_jthread // C++ >= 20 #include <atomic> #include <bits/std_thread.h> @@ -650,6 +649,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION stop_callback(stop_token, _Callback) -> stop_callback<_Callback>; _GLIBCXX_END_NAMESPACE_VERSION -} // namespace -#endif // __cplusplus > 201703L +} // namespace std +#endif // __glibcxx_jthread #endif // _GLIBCXX_STOP_TOKEN diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string index 6211da9..7186471 100644 --- a/libstdc++-v3/include/std/string +++ b/libstdc++-v3/include/std/string @@ -60,6 +60,7 @@ #define __glibcxx_want_allocator_traits_is_always_equal #define __glibcxx_want_constexpr_char_traits #define __glibcxx_want_constexpr_string +#define __glibcxx_want_containers_ranges #define __glibcxx_want_erase_if #define __glibcxx_want_nonmember_container_access #define __glibcxx_want_string_resize_and_overwrite diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index d2f91ad..0de08c0 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -297,7 +297,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #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 +309,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 +337,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..b39ce71 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -2939,19 +2939,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif #ifdef __cpp_lib_make_from_tuple // C++ >= 17 + template <typename _Tp, typename _Tuple, typename _Seq + = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>> + constexpr bool __can_make_from_tuple = false; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3528. make_from_tuple can perform (the equivalent of) a C-style cast + template <typename _Tp, typename _Tuple, size_t... _Idx> + constexpr bool __can_make_from_tuple<_Tp, _Tuple, index_sequence<_Idx...>> + = is_constructible_v<_Tp, + decltype(std::get<_Idx>(std::declval<_Tuple>()))...>; + template <typename _Tp, typename _Tuple, size_t... _Idx> constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>) - { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); } + { + static_assert(__can_make_from_tuple<_Tp, _Tuple, index_sequence<_Idx...>>); + return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); + } #if __cpp_lib_tuple_like // >= C++23 template <typename _Tp, __tuple_like _Tuple> #else template <typename _Tp, typename _Tuple> #endif - constexpr _Tp + constexpr auto make_from_tuple(_Tuple&& __t) noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>) +#ifdef __cpp_concepts // >= C++20 + -> _Tp + requires __can_make_from_tuple<_Tp, _Tuple> +#else + -> __enable_if_t<__can_make_from_tuple<_Tp, _Tuple>, _Tp> +#endif { constexpr size_t __n = tuple_size_v<remove_reference_t<_Tuple>>; #if __has_builtin(__reference_constructs_from_temporary) diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 676cdf2..0554111 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -280,11 +280,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Forward declarations template<typename> - struct is_reference; - template<typename> - struct is_function; - template<typename> - struct is_void; + struct is_object; template<typename> struct remove_cv; template<typename> @@ -294,21 +290,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename> struct __is_array_unknown_bounds; + // An object type which is not an unbounded array. + // It might still be an incomplete type, but if this is false_type + // then we can be certain it's not a complete object type. + template<typename _Tp> + using __maybe_complete_object_type + = __and_<is_object<_Tp>, __not_<__is_array_unknown_bounds<_Tp>>>; + // Helper functions that return false_type for incomplete classes, // incomplete unions and arrays of known bound from those. - template <typename _Tp, size_t = sizeof(_Tp)> - constexpr true_type __is_complete_or_unbounded(__type_identity<_Tp>) - { return {}; } - - template <typename _TypeIdentity, - typename _NestedType = typename _TypeIdentity::type> - constexpr typename __or_< - is_reference<_NestedType>, - is_function<_NestedType>, - is_void<_NestedType>, - __is_array_unknown_bounds<_NestedType> - >::type __is_complete_or_unbounded(_TypeIdentity) + // More specialized overload for complete object types (returning true_type). + template<typename _Tp, + typename = __enable_if_t<__maybe_complete_object_type<_Tp>::value>, + size_t = sizeof(_Tp)> + constexpr true_type + __is_complete_or_unbounded(__type_identity<_Tp>) + { return {}; }; + + // Less specialized overload for reference and unknown-bound array types + // (returning true_type), and incomplete types (returning false_type). + template<typename _TypeIdentity, + typename _NestedType = typename _TypeIdentity::type> + constexpr typename __not_<__maybe_complete_object_type<_NestedType>>::type + __is_complete_or_unbounded(_TypeIdentity) { return {}; } // __remove_cv_t (std::remove_cv_t for C++11). @@ -1036,9 +1041,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_array_unknown_bounds<_Tp[]> : public true_type { }; + /// @endcond // Destructible and constructible type properties. +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible) + /// is_destructible + template<typename _Tp> + struct is_destructible + : public __bool_constant<__is_destructible(_Tp)> + { }; +#else + /// @cond undocumented + // In N3290 is_destructible does not say anything about function // types and abstract types, see LWG 2049. This implementation // describes function types as non-destructible and all complete @@ -1090,7 +1105,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; +#endif +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible) + /// is_nothrow_destructible + template<typename _Tp> + struct is_nothrow_destructible + : public __bool_constant<__is_nothrow_destructible(_Tp)> + { }; +#else /// @cond undocumented // is_nothrow_destructible requires that is_destructible is @@ -1144,6 +1167,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; +#endif /// @cond undocumented template<typename _Tp, typename... _Args> @@ -1451,6 +1475,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION "template argument must be a complete class or an unbounded array"); }; +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible) + /// is_trivially_destructible + template<typename _Tp> + struct is_trivially_destructible + : public __bool_constant<__is_trivially_destructible(_Tp)> + { }; +#else /// is_trivially_destructible template<typename _Tp> struct is_trivially_destructible @@ -1460,7 +1491,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; - +#endif /// has_virtual_destructor template<typename _Tp> @@ -3212,7 +3243,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Fn, typename... _ArgTypes> struct __is_invocable +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable) + : __bool_constant<__is_invocable(_Fn, _ArgTypes...)> +#else : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type +#endif { }; template<typename _Fn, typename _Tp, typename... _Args> @@ -3263,8 +3298,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // __is_nothrow_invocable (std::is_nothrow_invocable for C++11) template<typename _Fn, typename... _Args> struct __is_nothrow_invocable +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable) + : __bool_constant<__is_nothrow_invocable(_Fn, _Args...)> +#else : __and_<__is_invocable<_Fn, _Args...>, __call_is_nothrow_<_Fn, _Args...>>::type +#endif { }; #pragma GCC diagnostic push @@ -3573,8 +3612,13 @@ template <typename _Tp> inline constexpr bool is_move_assignable_v = __is_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible) +template <typename _Tp> + inline constexpr bool is_destructible_v = __is_destructible(_Tp); +#else template <typename _Tp> inline constexpr bool is_destructible_v = is_destructible<_Tp>::value; +#endif template <typename _Tp, typename... _Args> inline constexpr bool is_trivially_constructible_v @@ -3601,7 +3645,11 @@ template <typename _Tp> = __is_trivially_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); -#if __cpp_concepts +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible) +template <typename _Tp> + inline constexpr bool is_trivially_destructible_v + = __is_trivially_destructible(_Tp); +#elif __cpp_concepts template <typename _Tp> inline constexpr bool is_trivially_destructible_v = false; @@ -3646,9 +3694,15 @@ template <typename _Tp> inline constexpr bool is_nothrow_move_assignable_v = __is_nothrow_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible) +template <typename _Tp> + inline constexpr bool is_nothrow_destructible_v + = __is_nothrow_destructible(_Tp); +#else template <typename _Tp> inline constexpr bool is_nothrow_destructible_v = is_nothrow_destructible<_Tp>::value; +#endif template <typename _Tp> inline constexpr bool has_virtual_destructor_v @@ -3704,10 +3758,19 @@ template <typename _From, typename _To> inline constexpr bool is_convertible_v = is_convertible<_From, _To>::value; #endif template<typename _Fn, typename... _Args> - inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value; + inline constexpr bool is_invocable_v +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable) + = __is_invocable(_Fn, _Args...); +#else + = is_invocable<_Fn, _Args...>::value; +#endif template<typename _Fn, typename... _Args> inline constexpr bool is_nothrow_invocable_v +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable) + = __is_nothrow_invocable(_Fn, _Args...); +#else = is_nothrow_invocable<_Fn, _Args...>::value; +#endif template<typename _Ret, typename _Fn, typename... _Args> inline constexpr bool is_invocable_r_v = is_invocable_r<_Ret, _Fn, _Args...>::value; @@ -4002,7 +4065,8 @@ template<typename _Ret, typename _Fn, typename... _Args> #ifdef __cpp_lib_is_constant_evaluated // C++ >= 20 && HAVE_IS_CONST_EVAL /// Returns true only when called during constant evaluation. /// @since C++20 - constexpr inline bool + [[__gnu__::__always_inline__]] + constexpr bool is_constant_evaluated() noexcept { #if __cpp_if_consteval >= 202106L diff --git a/libstdc++-v3/include/std/unordered_map b/libstdc++-v3/include/std/unordered_map index 37f2273..3ae25d7 100644 --- a/libstdc++-v3/include/std/unordered_map +++ b/libstdc++-v3/include/std/unordered_map @@ -49,6 +49,7 @@ #endif #define __glibcxx_want_allocator_traits_is_always_equal +#define __glibcxx_want_containers_ranges #define __glibcxx_want_erase_if #define __glibcxx_want_generic_unordered_lookup #define __glibcxx_want_node_extract diff --git a/libstdc++-v3/include/std/unordered_set b/libstdc++-v3/include/std/unordered_set index 4c73e5d..b561163 100644 --- a/libstdc++-v3/include/std/unordered_set +++ b/libstdc++-v3/include/std/unordered_set @@ -49,6 +49,7 @@ #endif #define __glibcxx_want_allocator_traits_is_always_equal +#define __glibcxx_want_containers_ranges #define __glibcxx_want_erase_if #define __glibcxx_want_generic_unordered_lookup #define __glibcxx_want_node_extract 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/vector b/libstdc++-v3/include/std/vector index 8bb2543..a98ffb1 100644 --- a/libstdc++-v3/include/std/vector +++ b/libstdc++-v3/include/std/vector @@ -81,6 +81,7 @@ #define __glibcxx_want_algorithm_default_value_type #define __glibcxx_want_allocator_traits_is_always_equal #define __glibcxx_want_constexpr_vector +#define __glibcxx_want_containers_ranges #define __glibcxx_want_erase_if #define __glibcxx_want_incomplete_container_elements #define __glibcxx_want_nonmember_container_access |