diff options
Diffstat (limited to 'libstdc++-v3/include/std')
59 files changed, 10379 insertions, 1584 deletions
diff --git a/libstdc++-v3/include/std/algorithm b/libstdc++-v3/include/std/algorithm index 321a5e2..1563cdf 100644 --- a/libstdc++-v3/include/std/algorithm +++ b/libstdc++-v3/include/std/algorithm @@ -74,6 +74,7 @@ #define __glibcxx_want_ranges_contains #define __glibcxx_want_ranges_find_last #define __glibcxx_want_ranges_fold +#define __glibcxx_want_ranges_starts_ends_with #define __glibcxx_want_robust_nonmodifying_seq_ops #define __glibcxx_want_sample #define __glibcxx_want_shift diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index fdcf0b0..12f0109 100644 --- a/libstdc++-v3/include/std/array +++ b/libstdc++-v3/include/std/array @@ -381,6 +381,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __one.swap(__two); } #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2766. Swapping non-swappable types template<typename _Tp, std::size_t _Nm> __enable_if_t<!__array_traits<_Tp, _Nm>::_Is_swappable::value> swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&) = delete; diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic index 9b1aca0..0a510d8 100644 --- a/libstdc++-v3/include/std/atomic +++ b/libstdc++-v3/include/std/atomic @@ -217,6 +217,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(sizeof(_Tp) > 0, "Incomplete or zero-sized types are not supported"); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4069. std::atomic<volatile T> should be ill-formed + static_assert(is_same<_Tp, typename remove_cv<_Tp>::type>::value, + "template argument for std::atomic must not be const or volatile"); + #if __cplusplus > 201703L static_assert(is_copy_constructible_v<_Tp>); static_assert(is_move_constructible_v<_Tp>); @@ -401,21 +406,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void wait(_Tp __old, memory_order __m = memory_order_seq_cst) const noexcept { - std::__atomic_wait_address_v(&_M_i, __old, - [__m, this] { return this->load(__m); }); + std::__atomic_wait_address_v(std::addressof(_M_i), __old, + [__m, this] { return this->load(__m); }); } // TODO add const volatile overload void notify_one() noexcept - { std::__atomic_notify_address(&_M_i, false); } + { std::__atomic_notify_address(std::addressof(_M_i), false); } void notify_all() noexcept - { std::__atomic_notify_address(&_M_i, true); } + { std::__atomic_notify_address(std::addressof(_M_i), true); } #endif // __cpp_lib_atomic_wait - }; /// Partial specialization for pointer types. diff --git a/libstdc++-v3/include/std/barrier b/libstdc++-v3/include/std/barrier index 6c3cfd4..56270c9 100644 --- a/libstdc++-v3/include/std/barrier +++ b/libstdc++-v3/include/std/barrier @@ -81,105 +81,142 @@ It looks different from literature pseudocode for two main reasons: enum class __barrier_phase_t : unsigned char { }; - template<typename _CompletionF> - class __tree_barrier + struct __tree_barrier_base + { + static constexpr ptrdiff_t + max() noexcept + { return __PTRDIFF_MAX__ - 1; } + + protected: + using __atomic_phase_ref_t = std::__atomic_ref<__barrier_phase_t>; + using __atomic_phase_const_ref_t = std::__atomic_ref<const __barrier_phase_t>; + static constexpr auto __phase_alignment = + __atomic_phase_ref_t::required_alignment; + + using __tickets_t = std::array<__barrier_phase_t, 64>; + struct alignas(64) /* naturally-align the heap state */ __state_t { - using __atomic_phase_ref_t = std::__atomic_ref<__barrier_phase_t>; - using __atomic_phase_const_ref_t = std::__atomic_ref<const __barrier_phase_t>; - static constexpr auto __phase_alignment = - __atomic_phase_ref_t::required_alignment; + alignas(__phase_alignment) __tickets_t __tickets; + }; - using __tickets_t = std::array<__barrier_phase_t, 64>; - struct alignas(64) /* naturally-align the heap state */ __state_t - { - alignas(__phase_alignment) __tickets_t __tickets; - }; + ptrdiff_t _M_expected; + __atomic_base<__state_t*> _M_state{nullptr}; + __atomic_base<ptrdiff_t> _M_expected_adjustment{0}; + alignas(__phase_alignment) __barrier_phase_t _M_phase{}; - ptrdiff_t _M_expected; - unique_ptr<__state_t[]> _M_state; - __atomic_base<ptrdiff_t> _M_expected_adjustment; - _CompletionF _M_completion; + explicit constexpr + __tree_barrier_base(ptrdiff_t __expected) + : _M_expected(__expected) + { + __glibcxx_assert(__expected >= 0 && __expected <= max()); - alignas(__phase_alignment) __barrier_phase_t _M_phase; + if (!std::is_constant_evaluated()) + _M_state.store(_M_alloc_state().release(), memory_order_release); + } - bool - _M_arrive(__barrier_phase_t __old_phase, size_t __current) - { - const auto __old_phase_val = static_cast<unsigned char>(__old_phase); - const auto __half_step = - static_cast<__barrier_phase_t>(__old_phase_val + 1); - const auto __full_step = - static_cast<__barrier_phase_t>(__old_phase_val + 2); + unique_ptr<__state_t[]> + _M_alloc_state() + { + size_t const __count = (_M_expected + 1) >> 1; + return std::make_unique<__state_t[]>(__count); + } - size_t __current_expected = _M_expected; - __current %= ((_M_expected + 1) >> 1); + bool + _M_arrive(__barrier_phase_t __old_phase, size_t __current) + { + const auto __old_phase_val = static_cast<unsigned char>(__old_phase); + const auto __half_step = + static_cast<__barrier_phase_t>(__old_phase_val + 1); + const auto __full_step = + static_cast<__barrier_phase_t>(__old_phase_val + 2); + + size_t __current_expected = _M_expected; + __current %= ((_M_expected + 1) >> 1); + + __state_t* const __state = _M_state.load(memory_order_relaxed); + + for (int __round = 0; ; ++__round) + { + if (__current_expected <= 1) + return true; + size_t const __end_node = ((__current_expected + 1) >> 1), + __last_node = __end_node - 1; + for ( ; ; ++__current) + { + if (__current == __end_node) + __current = 0; + auto __expect = __old_phase; + __atomic_phase_ref_t __phase(__state[__current] + .__tickets[__round]); + if (__current == __last_node && (__current_expected & 1)) + { + if (__phase.compare_exchange_strong(__expect, __full_step, + memory_order_acq_rel)) + break; // I'm 1 in 1, go to next __round + } + else if (__phase.compare_exchange_strong(__expect, __half_step, + memory_order_acq_rel)) + { + return false; // I'm 1 in 2, done with arrival + } + else if (__expect == __half_step) + { + if (__phase.compare_exchange_strong(__expect, __full_step, + memory_order_acq_rel)) + break; // I'm 2 in 2, go to next __round + } + } + __current_expected = __last_node + 1; + __current >>= 1; + } + } + }; - for (int __round = 0; ; ++__round) - { - if (__current_expected <= 1) - return true; - size_t const __end_node = ((__current_expected + 1) >> 1), - __last_node = __end_node - 1; - for ( ; ; ++__current) - { - if (__current == __end_node) - __current = 0; - auto __expect = __old_phase; - __atomic_phase_ref_t __phase(_M_state[__current] - .__tickets[__round]); - if (__current == __last_node && (__current_expected & 1)) - { - if (__phase.compare_exchange_strong(__expect, __full_step, - memory_order_acq_rel)) - break; // I'm 1 in 1, go to next __round - } - else if (__phase.compare_exchange_strong(__expect, __half_step, - memory_order_acq_rel)) - { - return false; // I'm 1 in 2, done with arrival - } - else if (__expect == __half_step) - { - if (__phase.compare_exchange_strong(__expect, __full_step, - memory_order_acq_rel)) - break; // I'm 2 in 2, go to next __round - } - } - __current_expected = __last_node + 1; - __current >>= 1; - } - } + template<typename _CompletionF> + class __tree_barrier : public __tree_barrier_base + { + [[no_unique_address]] _CompletionF _M_completion; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3898. Possibly unintended preconditions for completion functions + void _M_invoke_completion() noexcept { _M_completion(); } public: using arrival_token = __barrier_phase_t; - static constexpr ptrdiff_t - max() noexcept - { return __PTRDIFF_MAX__; } - + constexpr __tree_barrier(ptrdiff_t __expected, _CompletionF __completion) - : _M_expected(__expected), _M_expected_adjustment(0), - _M_completion(move(__completion)), - _M_phase(static_cast<__barrier_phase_t>(0)) - { - size_t const __count = (_M_expected + 1) >> 1; - - _M_state = std::make_unique<__state_t[]>(__count); - } + : __tree_barrier_base(__expected), _M_completion(std::move(__completion)) + { } [[nodiscard]] arrival_token arrive(ptrdiff_t __update) { + __glibcxx_assert(__update > 0); + // FIXME: Check that update is less than or equal to the expected count + // for the current barrier phase. + std::hash<std::thread::id> __hasher; size_t __current = __hasher(std::this_thread::get_id()); __atomic_phase_ref_t __phase(_M_phase); const auto __old_phase = __phase.load(memory_order_relaxed); const auto __cur = static_cast<unsigned char>(__old_phase); - for(; __update; --__update) + + if (__cur == 0 && !_M_state.load(memory_order_relaxed)) [[unlikely]] + { + auto __p = _M_alloc_state(); + __state_t* __val = nullptr; + if (_M_state.compare_exchange_strong(__val, __p.get(), + memory_order_seq_cst, + memory_order_acquire)) + __p.release(); + } + + for (; __update; --__update) { - if(_M_arrive(__old_phase, __current)) + if (_M_arrive(__old_phase, __current)) { - _M_completion(); + _M_invoke_completion(); _M_expected += _M_expected_adjustment.load(memory_order_relaxed); _M_expected_adjustment.store(0, memory_order_relaxed); auto __new_phase = static_cast<__barrier_phase_t>(__cur + 2); @@ -194,11 +231,7 @@ It looks different from literature pseudocode for two main reasons: wait(arrival_token&& __old_phase) const { __atomic_phase_const_ref_t __phase(_M_phase); - auto const __test_fn = [=] - { - return __phase.load(memory_order_acquire) != __old_phase; - }; - std::__atomic_wait_address(&_M_phase, __test_fn); + __phase.wait(__old_phase, memory_order_acquire); } void @@ -212,6 +245,8 @@ It looks different from literature pseudocode for two main reasons: template<typename _CompletionF = __empty_completion> class barrier { + static_assert(is_invocable_v<_CompletionF&>); + // Note, we may introduce a "central" barrier algorithm at some point // for more space constrained targets using __algorithm_t = __tree_barrier<_CompletionF>; @@ -236,7 +271,7 @@ It looks different from literature pseudocode for two main reasons: max() noexcept { return __algorithm_t::max(); } - explicit + constexpr explicit barrier(ptrdiff_t __count, _CompletionF __completion = _CompletionF()) : _M_b(__count, std::move(__completion)) { } diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit index a481781..fd75edf 100644 --- a/libstdc++-v3/include/std/bit +++ b/libstdc++-v3/include/std/bit @@ -153,18 +153,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // __cpp_lib_byteswap /// @cond undocumented +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr template<typename _Tp> constexpr _Tp __rotl(_Tp __x, int __s) noexcept { constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits; - if _GLIBCXX17_CONSTEXPR ((_Nd & (_Nd - 1)) == 0) + if constexpr ((_Nd & (_Nd - 1)) == 0) { // Variant for power of two _Nd which the compiler can // easily pattern match. constexpr unsigned __uNd = _Nd; - const unsigned __r = __s; + const auto __r = static_cast<unsigned>(__s); return (__x << (__r % __uNd)) | (__x >> ((-__r) % __uNd)); } const int __r = __s % _Nd; @@ -181,12 +183,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __rotr(_Tp __x, int __s) noexcept { constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits; - if _GLIBCXX17_CONSTEXPR ((_Nd & (_Nd - 1)) == 0) + if constexpr ((_Nd & (_Nd - 1)) == 0) { // Variant for power of two _Nd which the compiler can // easily pattern match. constexpr unsigned __uNd = _Nd; - const unsigned __r = __s; + const auto __r = static_cast<unsigned>(__s); return (__x >> (__r % __uNd)) | (__x << ((-__r) % __uNd)); } const int __r = __s % _Nd; @@ -215,17 +217,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto _Nd_ul = __int_traits<unsigned long>::__digits; constexpr auto _Nd_u = __int_traits<unsigned>::__digits; - if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u) + if constexpr (_Nd <= _Nd_u) { constexpr int __diff = _Nd_u - _Nd; return __builtin_clz(__x) - __diff; } - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ul) + else if constexpr (_Nd <= _Nd_ul) { constexpr int __diff = _Nd_ul - _Nd; return __builtin_clzl(__x) - __diff; } - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ull) + else if constexpr (_Nd <= _Nd_ull) { constexpr int __diff = _Nd_ull - _Nd; return __builtin_clzll(__x) - __diff; @@ -272,11 +274,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto _Nd_ul = __int_traits<unsigned long>::__digits; constexpr auto _Nd_u = __int_traits<unsigned>::__digits; - if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u) + if constexpr (_Nd <= _Nd_u) return __builtin_ctz(__x); - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ul) + else if constexpr (_Nd <= _Nd_ul) return __builtin_ctzl(__x); - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ull) + else if constexpr (_Nd <= _Nd_ull) return __builtin_ctzll(__x); else // (_Nd > _Nd_ull) { @@ -314,11 +316,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto _Nd_ul = __int_traits<unsigned long>::__digits; constexpr auto _Nd_u = __int_traits<unsigned>::__digits; - if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_u) + if constexpr (_Nd <= _Nd_u) return __builtin_popcount(__x); - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ul) + else if constexpr (_Nd <= _Nd_ul) return __builtin_popcountl(__x); - else if _GLIBCXX17_CONSTEXPR (_Nd <= _Nd_ull) + else if constexpr (_Nd <= _Nd_ull) return __builtin_popcountll(__x); else // (_Nd > _Nd_ull) { @@ -357,7 +359,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } using __promoted_type = decltype(__x << 1); - if _GLIBCXX17_CONSTEXPR (!is_same<__promoted_type, _Tp>::value) + if constexpr (!is_same<__promoted_type, _Tp>::value) { // If __x undergoes integral promotion then shifting by _Nd is // not undefined. In order to make the shift undefined, so that @@ -388,6 +390,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return _Nd - std::__countl_zero(__x); } +#pragma GCC diagnostic pop /// @endcond #ifdef __cpp_lib_bitops // C++ >= 20 diff --git a/libstdc++-v3/include/std/bitset b/libstdc++-v3/include/std/bitset index c07117a..ece3593 100644 --- a/libstdc++-v3/include/std/bitset +++ b/libstdc++-v3/include/std/bitset @@ -61,8 +61,13 @@ #endif #define __glibcxx_want_constexpr_bitset +#define __glibcxx_want_bitset // ...construct from string_view #include <bits/version.h> +#ifdef __cpp_lib_bitset // ...construct from string_view +# include <string_view> +#endif + #define _GLIBCXX_BITSET_BITS_PER_WORD (__CHAR_BIT__ * __SIZEOF_LONG__) #define _GLIBCXX_BITSET_WORDS(__n) \ ((__n) / _GLIBCXX_BITSET_BITS_PER_WORD + \ @@ -715,7 +720,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER namespace __bitset { -#if _GLIBCXX_HOSTED +#ifdef __cpp_lib_bitset // ...construct from string_view + template<typename _CharT> + using __string = std::basic_string_view<_CharT>; +#elif _GLIBCXX_HOSTED template<typename _CharT> using __string = std::basic_string<_CharT>; #else @@ -752,7 +760,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * (Note that %bitset does @e not meet the formal requirements of a * <a href="tables.html#65">container</a>. Mainly, it lacks iterators.) * - * The template argument, @a Nb, may be any non-negative number, + * The template argument, `Nb`, may be any non-negative number, * specifying the number of bits (e.g., "0", "12", "1024*1024"). * * In the general unoptimized case, storage is allocated in word-sized @@ -816,28 +824,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef _Base_bitset<_GLIBCXX_BITSET_WORDS(_Nb)> _Base; typedef unsigned long _WordT; -#if _GLIBCXX_HOSTED - template<class _CharT, class _Traits, class _Alloc> - _GLIBCXX23_CONSTEXPR - void - _M_check_initial_position(const std::basic_string<_CharT, _Traits, _Alloc>& __s, - size_t __position) const + template<class _Str> + _GLIBCXX23_CONSTEXPR void + _M_check_initial_position( + const _Str& __s, typename _Str::size_type __position) const { if (__position > __s.size()) - __throw_out_of_range_fmt(__N("bitset::bitset: __position " - "(which is %zu) > __s.size() " - "(which is %zu)"), - __position, __s.size()); + __throw_out_of_range_fmt( + __N("bitset::bitset:" + " __position (which is %zu) > __s.size() (which is %zu)"), + size_t(__position), size_t(__s.size())); } -#endif // HOSTED _GLIBCXX23_CONSTEXPR void _M_check(size_t __position, const char *__s) const { if (__position >= _Nb) - __throw_out_of_range_fmt(__N("%s: __position (which is %zu) " - ">= _Nb (which is %zu)"), - __s, __position, _Nb); + __throw_out_of_range_fmt( + __N("%s: __position (which is %zu) >= _Nb (which is %zu)"), + __s, size_t(__position), size_t(_Nb)); } _GLIBCXX23_CONSTEXPR @@ -954,12 +959,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if _GLIBCXX_HOSTED /** * Use a subset of a string. - * @param __s A string of @a 0 and @a 1 characters. - * @param __position Index of the first character in @a __s to use; + * @param __s A string of `0` and `1` characters. + * @param __position Index of the first character in `__s` to use; * defaults to zero. - * @throw std::out_of_range If @a pos is bigger the size of @a __s. + * @throw std::out_of_range If `__position > __s.size()`. * @throw std::invalid_argument If a character appears in the string - * which is neither @a 0 nor @a 1. + * which is neither `0` nor `1`. */ template<class _CharT, class _Traits, class _Alloc> _GLIBCXX23_CONSTEXPR @@ -976,13 +981,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /** * Use a subset of a string. - * @param __s A string of @a 0 and @a 1 characters. - * @param __position Index of the first character in @a __s to use. + * @param __s A string of `0` and `1` characters. + * @param __position Index of the first character in `__s` to use. * @param __n The number of characters to copy. - * @throw std::out_of_range If @a __position is bigger the size - * of @a __s. + * @throw std::out_of_range If `__position > __s.size()`. * @throw std::invalid_argument If a character appears in the string - * which is neither @a 0 nor @a 1. + * which is neither `0` nor `1`. */ template<class _CharT, class _Traits, class _Alloc> _GLIBCXX23_CONSTEXPR @@ -1008,17 +1012,50 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } #endif // HOSTED +#ifdef __cpp_lib_bitset // C++ >= 23 + /** + * Use a subset of a string view. + * @param __s A `string_view` of a sequence of `0` and `1` characters. + * @param __position Index of the first character in `__s` to use. + * @param __n The maximum number of characters from `__s` to use. + * @param __zero The character corresponding to the value 0. + * @param __one The character corresponding to the value 1. + * @throw std::out_of_range If `__position > __s.size()`. + * @throw std::invalid_argument If a character appears in `__s` + * which is neither `0` nor `1`. + */ + template<class _CharT, class _Traits> + constexpr explicit + bitset(basic_string_view<_CharT, _Traits> __s, + basic_string_view<_CharT, _Traits>::size_type __position = 0, + basic_string_view<_CharT, _Traits>::size_type __n = + basic_string_view<_CharT, _Traits>::npos, + _CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) + : _Base() + { + _M_check_initial_position(__s, __position); + _M_copy_from_ptr<_CharT, _Traits>( + __s.data(), __s.size(), __position, __n, __zero, __one); + } +#endif + #if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4294. bitset(const CharT*) constructor needs to be constrained /** * Construct from a character %array. - * @param __str An %array of characters @a zero and @a one. + * @param __str An %array of characters `__zero` and `__one`. * @param __n The number of characters to use. * @param __zero The character corresponding to the value 0. * @param __one The character corresponding to the value 1. * @throw std::invalid_argument If a character appears in the string - * which is neither @a __zero nor @a __one. + * which is neither `__zero` nor `__one`. */ - template<typename _CharT> + template<typename _CharT, + typename = _Require<is_trivially_copyable<_CharT>, + is_standard_layout<_CharT>, + is_trivially_default_constructible<_CharT>, + __not_<is_array<_CharT>>>> [[__gnu__::__nonnull__]] _GLIBCXX23_CONSTEXPR explicit @@ -1028,10 +1065,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) : _Base() { -#if _GLIBCXX_HOSTED if (!__str) __throw_logic_error(__N("bitset::bitset(const _CharT*, ...)")); -#endif using _Traits = typename __bitset::__string<_CharT>::traits_type; if (__n == __bitset::__string<_CharT>::npos) @@ -1514,7 +1549,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER size_t __pos, size_t __n, _CharT __zero, _CharT __one) { reset(); - const size_t __nbits = std::min(_Nb, std::min(__n, size_t(__len - __pos))); + const size_t __rlen = std::min(__n, size_t(__len - __pos)); + const size_t __nbits = std::min(_Nb, __rlen); + for (size_t __i = __rlen - __nbits; __i > 0; --__i) + { + const _CharT __c = __s[__pos + __rlen - __i]; + if (!_Traits::eq(__c, __zero) && !_Traits::eq(__c, __one)) + __throw_invalid_argument(__N("bitset::_M_copy_from_ptr")); + } for (size_t __i = __nbits; __i > 0; --__i) { const _CharT __c = __s[__pos + __nbits - __i]; @@ -1605,6 +1647,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef std::basic_istream<_CharT, _Traits> __istream_type; typedef typename __istream_type::ios_base __ios_base; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr struct _Buffer { static _GLIBCXX_CONSTEXPR bool _S_use_alloca() { return _Nb <= 256; } @@ -1613,18 +1657,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER ~_Buffer() { - if _GLIBCXX17_CONSTEXPR (!_S_use_alloca()) + if _GLIBCXX_CONSTEXPR (!_S_use_alloca()) delete[] _M_ptr; } _CharT* const _M_ptr; }; _CharT* __ptr; - if _GLIBCXX17_CONSTEXPR (_Buffer::_S_use_alloca()) + if _GLIBCXX_CONSTEXPR (_Buffer::_S_use_alloca()) __ptr = (_CharT*)__builtin_alloca(_Nb); else __ptr = new _CharT[_Nb]; const _Buffer __buf(__ptr); +#pragma GCC diagnostic pop // _GLIBCXX_RESOLVE_LIB_DEFECTS // 303. Bitset input operator underspecified @@ -1673,7 +1718,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { __is._M_setstate(__ios_base::badbit); } } - if _GLIBCXX17_CONSTEXPR (_Nb) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + if _GLIBCXX_CONSTEXPR (_Nb) { if (size_t __len = __ptr - __buf._M_ptr) __x.template _M_copy_from_ptr<_CharT, _Traits>(__buf._M_ptr, __len, @@ -1682,6 +1729,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER else __state |= __ios_base::failbit; } +#pragma GCC diagnostic pop if (__state) __is.setstate(__state); return __is; diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv index 75fcb71..47f5aaa 100644 --- a/libstdc++-v3/include/std/charconv +++ b/libstdc++-v3/include/std/charconv @@ -35,6 +35,7 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" // __int128 +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr #include <bits/requires_hosted.h> // for error codes @@ -239,7 +240,7 @@ namespace __detail to_chars_result __res; unsigned __len = 0; - if _GLIBCXX17_CONSTEXPR (__gnu_cxx::__int_traits<_Tp>::__digits <= 16) + if constexpr (__gnu_cxx::__int_traits<_Tp>::__digits <= 16) { __len = __val > 077777u ? 6u : __val > 07777u ? 5u @@ -336,7 +337,7 @@ namespace __detail *__first = '0'; return { __first + 1, errc{} }; } - else if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value) + else if constexpr (std::is_signed<_Tp>::value) if (__value < 0) { *__first++ = '-'; @@ -389,6 +390,10 @@ _GLIBCXX_TO_CHARS(unsigned __GLIBCXX_TYPE_INT_N_2) _GLIBCXX_TO_CHARS(signed __GLIBCXX_TYPE_INT_N_3) _GLIBCXX_TO_CHARS(unsigned __GLIBCXX_TYPE_INT_N_3) #endif +#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ +_GLIBCXX_TO_CHARS(signed __int128) +_GLIBCXX_TO_CHARS(unsigned __int128) +#endif #undef _GLIBCXX_TO_CHARS // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -452,7 +457,7 @@ namespace __detail _GLIBCXX20_CONSTEXPR unsigned char __from_chars_alnum_to_val(unsigned char __c) { - if _GLIBCXX17_CONSTEXPR (_DecOnly) + if constexpr (_DecOnly) return static_cast<unsigned char>(__c - '0'); else return __from_chars_alnum_to_val_table<_DecOnly>::value.__data[__c]; @@ -549,10 +554,10 @@ namespace __detail } // namespace __detail - /// std::from_chars for integral types. + /// std::from_chars for integer types. template<typename _Tp, - enable_if_t<__or_<__is_standard_integer<_Tp>, - is_same<char, remove_cv_t<_Tp>>>::value, int> = 0> + enable_if_t<__or_<__is_signed_or_unsigned_integer<_Tp>, + is_same<char, _Tp>>::value, int> = 0> _GLIBCXX23_CONSTEXPR from_chars_result from_chars(const char* __first, const char* __last, _Tp& __value, int __base = 10) @@ -562,7 +567,7 @@ namespace __detail from_chars_result __res{__first, {}}; int __sign = 1; - if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value) + if constexpr (std::is_signed<_Tp>::value) if (__first != __last && *__first == '-') { __sign = -1; @@ -595,7 +600,7 @@ namespace __detail __res.ec = errc::result_out_of_range; else { - if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value) + if constexpr (std::is_signed<_Tp>::value) { _Tp __tmp; if (__builtin_mul_overflow(__val, __sign, &__tmp)) @@ -605,8 +610,8 @@ namespace __detail } else { - if _GLIBCXX17_CONSTEXPR (__gnu_cxx::__int_traits<_Up>::__max - > __gnu_cxx::__int_traits<_Tp>::__max) + if constexpr (__gnu_cxx::__int_traits<_Up>::__max + > __gnu_cxx::__int_traits<_Tp>::__max) { if (__val > __gnu_cxx::__int_traits<_Tp>::__max) __res.ec = errc::result_out_of_range; diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono index 8eb9fd9..3e0cf42e 100644 --- a/libstdc++-v3/include/std/chrono +++ b/libstdc++-v3/include/std/chrono @@ -22,6 +22,8 @@ // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. +// [time] + /** @file include/chrono * This is a Standard C++ Library header. * @ingroup chrono @@ -42,23 +44,29 @@ # include <bits/c++0x_warning.h> #else +#define __glibcxx_want_chrono +#define __glibcxx_want_chrono_udls +#include <bits/version.h> + #include <bits/chrono.h> -#if __cplusplus >= 202002L +#if __cpp_lib_bitops >= 201907L # include <bit> // __countr_zero #endif -#if __cplusplus >= 202002L && _GLIBCXX_HOSTED +#ifdef __glibcxx_chrono_cxx20 +# include <bits/stl_algo.h> // upper_bound +# include <bits/range_access.h> // begin/end for arrays +#endif +#if __cpp_lib_chrono >= 201803L // C++20 && HOSTED && USE_CXX11_ABI # include <sstream> # include <string> # include <vector> -# include <bits/stl_algo.h> // upper_bound # include <bits/shared_ptr.h> # include <bits/unique_ptr.h> #endif - -#define __glibcxx_want_chrono -#define __glibcxx_want_chrono_udls -#include <bits/version.h> +#if __glibcxx_chrono_cxx20 >= 202306L // C++26 +# include <bits/functional_hash.h> +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -79,7 +87,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ namespace chrono { -#if __cplusplus >= 202002L +#ifdef __glibcxx_chrono_cxx20 /// @addtogroup chrono /// @{ struct local_t { }; @@ -175,13 +183,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using period = system_clock::period; using duration = chrono::duration<rep, period>; using time_point = chrono::time_point<tai_clock>; - static constexpr bool is_steady = false; // XXX true for CLOCK_TAI? + static constexpr bool is_steady = false; - // TODO move into lib, use CLOCK_TAI on linux, add extension point. [[nodiscard]] static time_point - now() - { return from_utc(utc_clock::now()); } + now(); // in src/c++20/clock.cc template<typename _Duration> [[nodiscard]] @@ -215,13 +221,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using period = system_clock::period; using duration = chrono::duration<rep, period>; using time_point = chrono::time_point<gps_clock>; - static constexpr bool is_steady = false; // XXX + static constexpr bool is_steady = false; - // TODO move into lib, add extension point. [[nodiscard]] static time_point - now() - { return from_utc(utc_clock::now()); } + now(); // in src/c++20/clock.cc template<typename _Duration> [[nodiscard]] @@ -2305,8 +2309,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __r *= 10; return __r; } - - template<typename _Duration> struct __utc_leap_second; } /// @endcond @@ -2481,30 +2483,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __byte_duration<ratio<1>> _M_s{}; bool _M_is_neg{}; __subseconds<precision> _M_ss{}; - - template<typename> friend struct __detail::__utc_leap_second; }; - /// @cond undocumented - namespace __detail - { - // Represents a time that is within a leap second insertion. - template<typename _Duration> - struct __utc_leap_second - { - explicit - __utc_leap_second(const sys_time<_Duration>& __s) - : _M_date(chrono::floor<days>(__s)), _M_time(__s - _M_date) - { - ++_M_time._M_s; - } - - sys_days _M_date; - hh_mm_ss<common_type_t<_Duration, days>> _M_time; - }; - } - /// @endcond - // 12/24 HOURS FUNCTIONS constexpr bool @@ -3345,7 +3325,328 @@ namespace __detail #endif // C++20 } // namespace chrono -#if __cplusplus >= 202002L +#if __glibcxx_chrono_cxx20 >= 202306 // C++26 + // Hash support [time.hash] + + template<typename _Tp> + concept __is_nothrow_copy_hashable = requires(const _Tp& __t) { + { hash<_Tp>{}(_Tp(__t)) } noexcept -> same_as<size_t>; + }; + + namespace chrono { + + template<typename _T1, typename... _Ts> + [[__gnu__::__always_inline__]] + constexpr auto + __pack_ints(_T1 __v1, _Ts... __vs) + { + using _ResT = decltype([] { + constexpr size_t __tsize = (sizeof(_T1) + ... + sizeof(_Ts)); + if constexpr (__tsize <= 1) + return static_cast<unsigned char>(0); + else if constexpr (__tsize <= 2) + return static_cast<__UINT16_TYPE__>(0); + else if constexpr (__tsize <= 4) + return static_cast<__UINT32_TYPE__>(0); + else if constexpr (__tsize <= 8) + return static_cast<__UINT64_TYPE__>(0); + else + static_assert(__tsize <= 8); + }()); + + _ResT __res = __v1; + ((__res = (__res << (sizeof(_Ts) * __CHAR_BIT__) | _ResT(__vs))), ...); + return __res; + } + + template<typename _Tp> + [[__gnu__::__always_inline__]] + constexpr auto + __as_int(_Tp __val) + { + if constexpr (is_same_v<_Tp, year>) + return static_cast<unsigned short>(static_cast<int>(__val)); + else if constexpr (is_same_v<_Tp, month> || is_same_v<_Tp, day>) + return static_cast<unsigned char>(static_cast<unsigned>(__val)); + else if constexpr (is_same_v<_Tp, weekday>) + return static_cast<unsigned char>(__val.c_encoding()); + else if constexpr (is_same_v<_Tp, weekday_indexed>) + return __pack_ints(chrono::__as_int(__val.weekday()), + static_cast<unsigned char>(__val.index())); + else if constexpr (is_same_v<_Tp, weekday_last>) + return chrono::__as_int(__val.weekday()); + else + static_assert(false); + } + + template<typename _Arg, typename... _Args> + size_t + __int_hash(_Arg __arg, _Args... __args) + { + static_assert((is_integral_v<_Arg> && ... && is_integral_v<_Args>)); + + // TODO consider using a better quality hasher + using _Hasher = _Hash_impl; + size_t __result = _Hasher::hash(__arg); + ((__result = _Hasher::__hash_combine(__args, __result)), ...); + return __result; + } + + template<typename... _Tps> + [[__gnu__::__always_inline__]] + inline size_t + __hash(_Tps... __vals) + { + if constexpr (sizeof...(_Tps) == 1) + return chrono::__int_hash(chrono::__as_int(__vals)...); + else + { + auto __res = chrono::__pack_ints(chrono::__as_int(__vals)...); + return chrono::__int_hash(__res); + } + } + } // namespace chrono + + // duration + template<typename _Rep, typename _Period> + requires __is_hash_enabled_for<_Rep> + struct hash<chrono::duration<_Rep, _Period>> + { + size_t + operator()(const chrono::duration<_Rep, _Period>& __val) const + noexcept(__is_nothrow_copy_hashable<_Rep>) + { + if constexpr (is_integral_v<_Rep>) + return chrono::__int_hash(__val.count()); + else + return hash<_Rep>{}(__val.count()); + } + }; + + template<typename _Rep, typename _Period> + struct __is_fast_hash<hash<chrono::duration<_Rep, _Period>>> + : __is_fast_hash<hash<_Rep>> + {}; + + // time_point + template<typename _Clock, typename _Dur> + requires __is_hash_enabled_for<_Dur> + struct hash<chrono::time_point<_Clock, _Dur>> + { + size_t + operator()(const chrono::time_point<_Clock, _Dur>& __val) const + noexcept(__is_nothrow_copy_hashable<_Dur>) + { return hash<_Dur>{}(__val.time_since_epoch()); } + }; + + template<typename _Clock, typename _Dur> + struct __is_fast_hash<hash<chrono::time_point<_Clock, _Dur>>> + : __is_fast_hash<hash<_Dur>> + {}; + + // day + template<> + struct hash<chrono::day> + { + size_t + operator()(chrono::day __val) const noexcept + { return chrono::__hash(__val); } + }; + + // month + template<> + struct hash<chrono::month> + { + size_t + operator()(chrono::month __val) const noexcept + { return chrono::__hash(__val); } + }; + + // year + template<> + struct hash<chrono::year> + { + size_t + operator()(chrono::year __val) const noexcept + { return chrono::__hash(__val); } + }; + + // weekday + template<> + struct hash<chrono::weekday> + { + size_t + operator()(chrono::weekday __val) const noexcept + { return chrono::__hash(__val); } + }; + + // weekday_indexed + template<> + struct hash<chrono::weekday_indexed> + { + size_t + operator()(chrono::weekday_indexed __val) const noexcept + { return chrono::__hash(__val); } + }; + + // weekday_last + template<> + struct hash<chrono::weekday_last> + { + size_t + operator()(chrono::weekday_last __val) const noexcept + { return chrono::__hash(__val); } + }; + + // month_day + template<> + struct hash<chrono::month_day> + { + size_t + operator()(chrono::month_day __val) const noexcept + { return chrono::__hash(__val.month(), __val.day()); } + }; + + // month_day_last + template<> + struct hash<chrono::month_day_last> + { + size_t operator()(chrono::month_day_last __val) const noexcept + { return chrono::__hash(__val.month()); } + }; + + // month_weekday + template<> + struct hash<chrono::month_weekday> + { + size_t + operator()(chrono::month_weekday __val) const noexcept + { return chrono::__hash(__val.month(), __val.weekday_indexed()); } + }; + + // month_weekday_last + template<> + struct hash<chrono::month_weekday_last> + { + size_t + operator()(chrono::month_weekday_last __val) const noexcept + { return chrono::__hash(__val.month(), __val.weekday_last()); } + }; + + // year_month + template<> + struct hash<chrono::year_month> + { + size_t + operator()(chrono::year_month __val) const noexcept + { return chrono::__hash(__val.year(), __val.month()); } + }; + + // year_month_day + template<> + struct hash<chrono::year_month_day> + { + size_t + operator()(chrono::year_month_day __val) const noexcept + { return chrono::__hash(__val.year(), __val.month(), __val.day()); } + }; + + // year_month_day_last + template<> + struct hash<chrono::year_month_day_last> + { + size_t + operator()(chrono::year_month_day_last __val) const noexcept + { return chrono::__hash(__val.year(), __val.month()); } + }; + + // year_month_weekday + template<> + struct hash<chrono::year_month_weekday> + { + size_t + operator()(chrono::year_month_weekday __val) const noexcept + { + return chrono::__hash(__val.year(), __val.month(), + __val.weekday_indexed()); + } + }; + + // year_month_weekday_last + template<> + struct hash<chrono::year_month_weekday_last> + { + size_t + operator()(chrono::year_month_weekday_last __val) const noexcept + { + return chrono::__hash(__val.year(), __val.month(), + __val.weekday_last()); + } + }; + +#if _GLIBCXX_HOSTED +#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI + // zoned_time + template<typename _Duration, typename _TimeZonePtr> + requires __is_hash_enabled_for< + typename chrono::zoned_time<_Duration, _TimeZonePtr>::duration> + && __is_hash_enabled_for<_TimeZonePtr> + struct hash<chrono::zoned_time<_Duration, _TimeZonePtr>> + { + private: + using _ActualDuration = + typename chrono::zoned_time<_Duration, _TimeZonePtr>::duration; + + public: + size_t + operator()(const chrono::zoned_time<_Duration, _TimeZonePtr>& __val) const + noexcept(__is_nothrow_copy_hashable<_ActualDuration> + && __is_nothrow_copy_hashable<_TimeZonePtr>) + { + const auto __iduration = [&] { + const _ActualDuration __sd = __val.get_sys_time().time_since_epoch(); + if constexpr (is_integral_v<typename _ActualDuration::rep>) + return __sd.count(); + else + return hash<_ActualDuration>{}(__sd); + }(); + + const auto __izone = [&] { + const _TimeZonePtr __tz = __val.get_time_zone(); + if constexpr (is_same_v<_TimeZonePtr, const chrono::time_zone*>) + return reinterpret_cast<uintptr_t>(__tz); + else + return hash<_TimeZonePtr>{}(__tz); + }(); + + return chrono::__int_hash(__iduration, __izone); + } + }; + + template<typename _Duration, typename _TimeZonePtr> + struct __is_fast_hash<hash<chrono::zoned_time<_Duration, _TimeZonePtr>>> + : __and_<__is_fast_hash<hash< + typename chrono::zoned_time<_Duration, _TimeZonePtr>::duration>>, + __is_fast_hash<hash<_TimeZonePtr>>> + {}; + + // leap_second + template<> + struct hash<chrono::leap_second> + { + size_t + operator()(chrono::leap_second __val) const noexcept + { + return chrono::__int_hash( + __val.date().time_since_epoch().count(), + __val.value().count()); + } + }; +#endif // _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI +#endif // _GLIBCXX_HOSTED +#endif // __glibcxx_chrono_cxx20 >= 202306 + +#ifdef __glibcxx_chrono_cxx20 inline namespace literals { inline namespace chrono_literals @@ -3374,7 +3675,7 @@ namespace __detail _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#if __cplusplus >= 202002L && _GLIBCXX_HOSTED +#if defined __glibcxx_chrono_cxx20 && _GLIBCXX_HOSTED # include <bits/chrono_io.h> #endif diff --git a/libstdc++-v3/include/std/complex b/libstdc++-v3/include/std/complex index 59ef905..4765425 100644 --- a/libstdc++-v3/include/std/complex +++ b/libstdc++-v3/include/std/complex @@ -96,7 +96,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> _GLIBCXX20_CONSTEXPR complex<_Tp> conj(const complex<_Tp>&); /// Return complex with magnitude @a rho and angle @a theta. - template<typename _Tp> complex<_Tp> polar(const _Tp&, const _Tp& = 0); + template<typename _Tp> complex<_Tp> polar(const _Tp&, const _Tp& = _Tp(0)); // Transcendentals: /// Return complex cosine of @a z. @@ -969,7 +969,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif - // 26.2.7/4: arg(__z): Returns the phase angle of __z. + // C++11 26.4.7 [complex.value.ops]/4: arg(z): Returns the phase angle of z. template<typename _Tp> inline _Tp __complex_arg(const complex<_Tp>& __z) @@ -1038,7 +1038,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline complex<_Tp> polar(const _Tp& __rho, const _Tp& __theta) { - __glibcxx_assert( __rho >= 0 ); + __glibcxx_assert( __rho >= _Tp(0) ); return complex<_Tp>(__rho * cos(__theta), __rho * sin(__theta)); } @@ -1238,13 +1238,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__x == _Tp()) { - _Tp __t = sqrt(abs(__y) / 2); + _Tp __t = sqrt(abs(__y) / _Tp(2)); return complex<_Tp>(__t, __y < _Tp() ? -__t : __t); } else { - _Tp __t = sqrt(2 * (std::abs(__z) + abs(__x))); - _Tp __u = __t / 2; + _Tp __t = sqrt(_Tp(2) * (std::abs(__z) + abs(__x))); + _Tp __u = __t / _Tp(2); return __x > _Tp() ? complex<_Tp>(__u, __y / __t) : complex<_Tp>(abs(__y) / __t, __y < _Tp() ? -__u : __u); @@ -1334,7 +1334,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION complex<_Tp> __complex_pow_unsigned(complex<_Tp> __x, unsigned __n) { - complex<_Tp> __y = __n % 2 ? __x : complex<_Tp>(1); + complex<_Tp> __y = __n % 2 ? __x : complex<_Tp>(_Tp(1)); while (__n >>= 1) { @@ -1357,7 +1357,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION pow(const complex<_Tp>& __z, int __n) { return __n < 0 - ? complex<_Tp>(1) / std::__complex_pow_unsigned(__z, -(unsigned)__n) + ? complex<_Tp>(_Tp(1)) / std::__complex_pow_unsigned(__z, + -(unsigned)__n) : std::__complex_pow_unsigned(__z, __n); } @@ -2123,8 +2124,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> std::complex<_Tp> acosh(const std::complex<_Tp>&); template<typename _Tp> std::complex<_Tp> asinh(const std::complex<_Tp>&); template<typename _Tp> std::complex<_Tp> atanh(const std::complex<_Tp>&); - // DR 595. - template<typename _Tp> _Tp fabs(const std::complex<_Tp>&); template<typename _Tp> inline std::complex<_Tp> @@ -2309,7 +2308,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION acos(const std::complex<_Tp>& __z) { return __complex_acos(__z.__rep()); } #else - /// acos(__z) [8.1.2]. + /// acos(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function cacos, defined // in subclause 7.3.5.1. template<typename _Tp> @@ -2345,7 +2344,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION asin(const std::complex<_Tp>& __z) { return __complex_asin(__z.__rep()); } #else - /// asin(__z) [8.1.3]. + /// asin(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function casin, defined // in subclause 7.3.5.2. template<typename _Tp> @@ -2389,7 +2388,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION atan(const std::complex<_Tp>& __z) { return __complex_atan(__z.__rep()); } #else - /// atan(__z) [8.1.4]. + /// atan(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function catan, defined // in subclause 7.3.5.3. template<typename _Tp> @@ -2425,7 +2424,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION acosh(const std::complex<_Tp>& __z) { return __complex_acosh(__z.__rep()); } #else - /// acosh(__z) [8.1.5]. + /// acosh(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function cacosh, defined // in subclause 7.3.6.1. template<typename _Tp> @@ -2464,7 +2463,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION asinh(const std::complex<_Tp>& __z) { return __complex_asinh(__z.__rep()); } #else - /// asinh(__z) [8.1.6]. + /// asinh(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function casin, defined // in subclause 7.3.6.2. template<typename _Tp> @@ -2508,7 +2507,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION atanh(const std::complex<_Tp>& __z) { return __complex_atanh(__z.__rep()); } #else - /// atanh(__z) [8.1.7]. + /// atanh(__z) C++11 26.4.8 [complex.transcendentals] // Effects: Behaves the same as C99 function catanh, defined // in subclause 7.3.6.3. template<typename _Tp> @@ -2518,22 +2517,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif template<typename _Tp> + _GLIBCXX11_DEPRECATED_SUGGEST("std::abs") inline _Tp - /// fabs(__z) [8.1.8]. + /// fabs(__z) TR1 8.1.8 [tr.c99.cmplx.fabs] // Effects: Behaves the same as C99 function cabs, defined // in subclause 7.3.8.1. fabs(const std::complex<_Tp>& __z) { return std::abs(__z); } - /// Additional overloads [8.1.9]. + // Additional overloads C++11 26.4.9 [cmplx.over] + template<typename _Tp> inline typename __gnu_cxx::__promote<_Tp>::__type arg(_Tp __x) { typedef typename __gnu_cxx::__promote<_Tp>::__type __type; #if (_GLIBCXX11_USE_C99_MATH && !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) - return std::signbit(__x) ? __type(3.1415926535897932384626433832795029L) - : __type(); + return __builtin_signbit(__type(__x)) + ? __type(3.1415926535897932384626433832795029L) : __type(); #else return std::arg(std::complex<__type>(__x)); #endif diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts index 5899f03..870b0a4 100644 --- a/libstdc++-v3/include/std/concepts +++ b/libstdc++-v3/include/std/concepts @@ -204,7 +204,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { private: template<typename _Tp, typename _Up> - static constexpr bool + static consteval bool _S_noexcept() { if constexpr (__adl_swap<_Tp, _Up>) @@ -296,6 +296,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { { !static_cast<_Tp&&>(__t) } -> __boolean_testable_impl; }; } // namespace __detail + // [concept.comparisoncommontype], helpers for comparison common types + namespace __detail + { + template<typename _Tp, typename _Up, + typename _Cref = common_reference_t<const _Tp&, const _Up&>> + concept __comparison_common_type_with_impl + = same_as<common_reference_t<const _Tp&, const _Up&>, + common_reference_t<const _Up&, const _Tp&>> + && requires { + requires convertible_to<const _Tp&, const _Cref&> + || convertible_to<_Tp, const _Cref&>; + requires convertible_to<const _Up&, const _Cref&> + || convertible_to<_Up, const _Cref&>; + }; + + template<typename _Tp, typename _Up> + concept __comparison_common_type_with + = __comparison_common_type_with_impl<remove_cvref_t<_Tp>, + remove_cvref_t<_Up>>; + } // namespace __detail + // [concept.equalitycomparable], concept equality_comparable namespace __detail @@ -316,7 +337,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Up> concept equality_comparable_with = equality_comparable<_Tp> && equality_comparable<_Up> - && common_reference_with<__detail::__cref<_Tp>, __detail::__cref<_Up>> + && __detail::__comparison_common_type_with<_Tp, _Up> && equality_comparable<common_reference_t<__detail::__cref<_Tp>, __detail::__cref<_Up>>> && __detail::__weakly_eq_cmp_with<_Tp, _Up>; diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable index 3525ff3..dcf0b92 100644 --- a/libstdc++-v3/include/std/condition_variable +++ b/libstdc++-v3/include/std/condition_variable @@ -193,15 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __wait_until_impl(unique_lock<mutex>& __lock, const chrono::time_point<steady_clock, _Dur>& __atime) { - auto __s = chrono::time_point_cast<chrono::seconds>(__atime); - auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); - - __gthread_time_t __ts = - { - static_cast<std::time_t>(__s.time_since_epoch().count()), - static_cast<long>(__ns.count()) - }; - + __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime); _M_cond.wait_until(*__lock.mutex(), CLOCK_MONOTONIC, __ts); return (steady_clock::now() < __atime @@ -214,15 +206,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __wait_until_impl(unique_lock<mutex>& __lock, const chrono::time_point<system_clock, _Dur>& __atime) { - auto __s = chrono::time_point_cast<chrono::seconds>(__atime); - auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); - - __gthread_time_t __ts = - { - static_cast<std::time_t>(__s.time_since_epoch().count()), - static_cast<long>(__ns.count()) - }; - + __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime); _M_cond.wait_until(*__lock.mutex(), __ts); return (system_clock::now() < __atime diff --git a/libstdc++-v3/include/std/debugging b/libstdc++-v3/include/std/debugging new file mode 100644 index 0000000..4cf7e4a --- /dev/null +++ b/libstdc++-v3/include/std/debugging @@ -0,0 +1,77 @@ +// Debugging support -*- C++ -*- + +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file include/debugging + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_DEBUGGING +#define _GLIBCXX_DEBUGGING 1 + +#define __glibcxx_want_debugging +#include <bits/version.h> + +#if __cpp_lib_debugging // C++ >= 26 +namespace std _GLIBCXX_VISIBILITY(default) +{ +// N.B. _GLIBCXX_BEGIN_NAMESPACE_VERSION is not used here. + +/** Try to determine if the program is running under control of a debugger. + * + * On GNU/Linux systems this function will only return true if the program + * is being traced by another program which is known to be a debugger. + * This is determined by checking the command name of the tracing program + * against a list of known debuggers, such as "gdb". + * + * On other POSIX-based systems, this function will return true if the + * program is being traced by any other process, which means it can return + * true for non-debugger utilities that use the ptrace system call. + * + * @since C++26 + */ +bool +is_debugger_present() noexcept; + +/** Stop the program with a breakpoint or debug trap. + * + * The details of how a breakpoint is implemented are platform-specific. + * Some systems provide a special instruction, such as `int3` in x86. + * When no more appropriate mechanism is available, this will stop the + * program using `__builtin_trap()`. It might not be possible for the + * program to continue after such a breakpoint. + * + * @since C++26 + */ +void +breakpoint() noexcept; + +/** Stop the program if it is running under control of a debugger. + * + * @since C++26 + */ +void +breakpoint_if_debugging() noexcept; + +} // namespace std +#endif +#endif // _GLIBCXX_DEBUGGING diff --git a/libstdc++-v3/include/std/deque b/libstdc++-v3/include/std/deque index 8fd7300..600f607 100644 --- a/libstdc++-v3/include/std/deque +++ b/libstdc++-v3/include/std/deque @@ -66,12 +66,12 @@ #include <bits/stl_construct.h> #include <bits/stl_uninitialized.h> #include <bits/stl_deque.h> -#include <bits/refwrap.h> #include <bits/range_access.h> #include <bits/deque.tcc> #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> @@ -100,19 +100,16 @@ namespace std _GLIBCXX_VISIBILITY(default) _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Alloc, typename _Predicate> - inline typename deque<_Tp, _Alloc>::size_type - erase_if(deque<_Tp, _Alloc>& __cont, _Predicate __pred) + inline typename _GLIBCXX_STD_C::deque<_Tp, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::deque<_Tp, _Alloc>& __cont, _Predicate __pred) { - using namespace __gnu_cxx; - _GLIBCXX_STD_C::deque<_Tp, _Alloc>& __ucont = __cont; const auto __osz = __cont.size(); - const auto __end = __ucont.end(); - auto __removed = std::__remove_if(__ucont.begin(), __end, - __ops::__pred_iter(std::ref(__pred))); + const auto __end = __cont.end(); + auto __removed = std::__remove_if(__cont.begin(), __end, + std::move(__pred)); if (__removed != __end) { - __cont.erase(__niter_wrap(__cont.begin(), __removed), - __cont.end()); + __cont.erase(__removed, __end); return __osz - __cont.size(); } @@ -121,24 +118,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Alloc, typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)> - inline typename deque<_Tp, _Alloc>::size_type - erase(deque<_Tp, _Alloc>& __cont, const _Up& __value) - { - using namespace __gnu_cxx; - _GLIBCXX_STD_C::deque<_Tp, _Alloc>& __ucont = __cont; - const auto __osz = __cont.size(); - const auto __end = __ucont.end(); - auto __removed = std::__remove_if(__ucont.begin(), __end, - __ops::__iter_equals_val(__value)); - if (__removed != __end) - { - __cont.erase(__niter_wrap(__cont.begin(), __removed), - __cont.end()); - return __osz - __cont.size(); - } + inline typename _GLIBCXX_STD_C::deque<_Tp, _Alloc>::size_type + erase(_GLIBCXX_STD_C::deque<_Tp, _Alloc>& __cont, const _Up& __value) + { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); } - return 0; - } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cpp_lib_erase_if diff --git a/libstdc++-v3/include/std/expected b/libstdc++-v3/include/std/expected index 5dc1dfb..a03a7d3 100644 --- a/libstdc++-v3/include/std/expected +++ b/libstdc++-v3/include/std/expected @@ -474,6 +474,7 @@ namespace __expected template<typename _Up = remove_cv_t<_Tp>> requires (!is_same_v<remove_cvref_t<_Up>, expected>) && (!is_same_v<remove_cvref_t<_Up>, in_place_t>) + && (!is_same_v<remove_cvref_t<_Up>, unexpect_t>) && is_constructible_v<_Tp, _Up> && (!__expected::__is_unexpected<remove_cvref_t<_Up>>) && __expected::__not_constructing_bool_from_expected<_Tp, _Up> @@ -821,32 +822,36 @@ namespace __expected return std::move(_M_unex); } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4406. value_or return statement is inconsistent with Mandates template<typename _Up = remove_cv_t<_Tp>> - constexpr _Tp + constexpr remove_cv_t<_Tp> value_or(_Up&& __v) const & noexcept(__and_v<is_nothrow_copy_constructible<_Tp>, is_nothrow_convertible<_Up, _Tp>>) { - static_assert( is_copy_constructible_v<_Tp> ); + using _Xp = remove_cv_t<_Tp>; + static_assert( is_convertible_v<const _Tp&, _Xp> ); static_assert( is_convertible_v<_Up, _Tp> ); if (_M_has_value) return _M_val; - return static_cast<_Tp>(std::forward<_Up>(__v)); + return std::forward<_Up>(__v); } template<typename _Up = remove_cv_t<_Tp>> - constexpr _Tp + constexpr remove_cv_t<_Tp> value_or(_Up&& __v) && noexcept(__and_v<is_nothrow_move_constructible<_Tp>, is_nothrow_convertible<_Up, _Tp>>) { - static_assert( is_move_constructible_v<_Tp> ); - static_assert( is_convertible_v<_Up, _Tp> ); + using _Xp = remove_cv_t<_Tp>; + static_assert( is_convertible_v<_Tp, _Xp> ); + static_assert( is_convertible_v<_Up, _Xp> ); if (_M_has_value) return std::move(_M_val); - return static_cast<_Tp>(std::forward<_Up>(__v)); + return std::forward<_Up>(__v); } template<typename _Gr = _Er> @@ -1158,35 +1163,47 @@ namespace __expected { __t == __u } -> convertible_to<bool>; { __e == __e2 } -> convertible_to<bool>; } + [[nodiscard]] friend constexpr bool operator==(const expected& __x, const expected<_Up, _Er2>& __y) noexcept(noexcept(bool(*__x == *__y)) && noexcept(bool(__x.error() == __y.error()))) { + if (__x.has_value() != __y.has_value()) + return false; if (__x.has_value()) - return __y.has_value() && bool(*__x == *__y); - else - return !__y.has_value() && bool(__x.error() == __y.error()); + return *__x == *__y; + return __x.error() == __y.error(); } - template<typename _Up> + template<typename _Up, same_as<_Tp> _Vp> requires (!__expected::__is_expected<_Up>) && requires (const _Tp& __t, const _Up& __u) { { __t == __u } -> convertible_to<bool>; } + [[nodiscard]] friend constexpr bool - operator==(const expected& __x, const _Up& __v) + operator==(const expected<_Vp, _Er>& __x, const _Up& __v) noexcept(noexcept(bool(*__x == __v))) - { return __x.has_value() && bool(*__x == __v); } + { + if (__x.has_value()) + return *__x == __v; + return false; + } template<typename _Er2> requires requires (const _Er& __e, const _Er2& __e2) { { __e == __e2 } -> convertible_to<bool>; } + [[nodiscard]] friend constexpr bool operator==(const expected& __x, const unexpected<_Er2>& __e) noexcept(noexcept(bool(__x.error() == __e.error()))) - { return !__x.has_value() && bool(__x.error() == __e.error()); } + { + if (!__x.has_value()) + return __x.error() == __e.error(); + return false; + } friend constexpr void swap(expected& __x, expected& __y) @@ -1836,24 +1853,31 @@ namespace __expected && requires (const _Er& __e, const _Er2& __e2) { { __e == __e2 } -> convertible_to<bool>; } + [[nodiscard]] friend constexpr bool operator==(const expected& __x, const expected<_Up, _Er2>& __y) noexcept(noexcept(bool(__x.error() == __y.error()))) { + if (__x.has_value() != __y.has_value()) + return false; if (__x.has_value()) - return __y.has_value(); - else - return !__y.has_value() && bool(__x.error() == __y.error()); + return true; + return __x.error() == __y.error(); } template<typename _Er2> requires requires (const _Er& __e, const _Er2& __e2) { { __e == __e2 } -> convertible_to<bool>; } + [[nodiscard]] friend constexpr bool operator==(const expected& __x, const unexpected<_Er2>& __e) noexcept(noexcept(bool(__x.error() == __e.error()))) - { return !__x.has_value() && bool(__x.error() == __e.error()); } + { + if (!__x.has_value()) + return __x.error() == __e.error(); + return false; + } friend constexpr void swap(expected& __x, expected& __y) diff --git a/libstdc++-v3/include/std/flat_map b/libstdc++-v3/include/std/flat_map index 405caa8..e48c3ea 100644 --- a/libstdc++-v3/include/std/flat_map +++ b/libstdc++-v3/include/std/flat_map @@ -873,7 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION [[nodiscard]] friend bool operator==(const _Derived& __x, const _Derived& __y) - { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); } + { + return __x._M_cont.keys == __y._M_cont.keys + && __x._M_cont.values == __y._M_cont.values; + } template<typename _Up = value_type> [[nodiscard]] @@ -890,14 +893,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __x.swap(__y); } template<typename _Predicate> - friend size_type - erase_if(_Derived& __c, _Predicate __pred) + size_type + _M_erase_if(_Predicate __pred) { - auto __guard = __c._M_make_clear_guard(); - auto __zv = views::zip(__c._M_cont.keys, __c._M_cont.values); - auto __sr = ranges::remove_if(__zv, __pred); + auto __guard = _M_make_clear_guard(); + auto __zv = views::zip(_M_cont.keys, _M_cont.values); + auto __sr = ranges::remove_if(__zv, __pred, + [](const auto& __e) { + return const_reference(__e); + }); auto __erased = __sr.size(); - __c.erase(__c.end() - __erased, __c.end()); + erase(end() - __erased, end()); __guard._M_disable(); return __erased; } @@ -947,7 +953,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: using iterator_category = input_iterator_tag; using iterator_concept = random_access_iterator_tag; - using value_type = pair<const key_type, mapped_type>; + using value_type = pair<key_type, mapped_type>; using reference = pair<const key_type&, ranges::__maybe_const_t<_Const, mapped_type>&>; using difference_type = ptrdiff_t; @@ -1142,14 +1148,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // element access mapped_type& operator[](const key_type& __x) - { return operator[]<const key_type>(__x); } + { return try_emplace(__x).first->second; } mapped_type& operator[](key_type&& __x) - { return operator[]<key_type>(std::move(__x)); } + { return try_emplace(std::move(__x)).first->second; } template<typename _Key2> - requires same_as<remove_cvref_t<_Key2>, _Key> || __transparent_comparator<_Compare> + requires __transparent_comparator<_Compare> mapped_type& operator[](_Key2&& __x) { return try_emplace(std::forward<_Key2>(__x)).first->second; } @@ -1329,6 +1335,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Impl::lower_bound; using _Impl::upper_bound; using _Impl::equal_range; + + using _Impl::_M_erase_if; }; template<typename _KeyContainer, typename _MappedContainer, @@ -1412,6 +1420,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && uses_allocator_v<_MappedContainer, _Alloc>> { }; + template<typename _Key, typename _Tp, typename _Compare, + typename _KeyContainer, typename _MappedContainer, typename _Predicate> + typename flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>::size_type + erase_if(flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& __c, + _Predicate __pred) + { return __c._M_erase_if(std::move(__pred)); } + /* Class template flat_multimap - container adaptor * * @ingroup @@ -1487,6 +1502,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Impl::lower_bound; using _Impl::upper_bound; using _Impl::equal_range; + + using _Impl::_M_erase_if; }; template<typename _KeyContainer, typename _MappedContainer, @@ -1571,6 +1588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && uses_allocator_v<_MappedContainer, _Alloc>> { }; + template<typename _Key, typename _Tp, typename _Compare, + typename _KeyContainer, typename _MappedContainer, typename _Predicate> + typename flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>::size_type + erase_if(flat_multimap<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& __c, + _Predicate __pred) + { return __c._M_erase_if(std::move(__pred)); } + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cpp_lib_flat_map diff --git a/libstdc++-v3/include/std/flat_set b/libstdc++-v3/include/std/flat_set index 3e15d1a..c48340d 100644 --- a/libstdc++-v3/include/std/flat_set +++ b/libstdc++-v3/include/std/flat_set @@ -745,15 +745,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __x.swap(__y); } template<typename _Predicate> - friend size_type - erase_if(_Derived& __c, _Predicate __pred) + size_type + _M_erase_if(_Predicate __pred) { - auto __guard = __c._M_make_clear_guard(); - auto __first = __c._M_cont.begin(); - auto __last = __c._M_cont.end(); + auto __guard = _M_make_clear_guard(); + auto __first = _M_cont.begin(); + auto __last = _M_cont.end(); __first = std::remove_if(__first, __last, __pred); auto __n = __last - __first; - __c.erase(__first, __last); + erase(__first, __last); __guard._M_disable(); return __n; } @@ -860,6 +860,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Impl::lower_bound; using _Impl::upper_bound; using _Impl::equal_range; + + using _Impl::_M_erase_if; }; template<typename _KeyContainer, @@ -930,6 +932,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : bool_constant<uses_allocator_v<_KeyContainer, _Alloc>> { }; + template<typename _Key, typename _Compare, typename _KeyContainer, + typename _Predicate> + typename flat_set<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_set<_Key, _Compare, _KeyContainer>& __c, _Predicate __pred) + { return __c._M_erase_if(std::move(__pred)); } + /* Class template flat_multiset - container adaptor * * @ingroup @@ -999,6 +1007,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Impl::lower_bound; using _Impl::upper_bound; using _Impl::equal_range; + + using _Impl::_M_erase_if; }; template<typename _KeyContainer, @@ -1069,6 +1079,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : bool_constant<uses_allocator_v<_KeyContainer, _Alloc>> { }; + template<typename _Key, typename _Compare, typename _KeyContainer, + typename _Predicate> + typename flat_multiset<_Key, _Compare, _KeyContainer>::size_type + erase_if(flat_multiset<_Key, _Compare, _KeyContainer>& __c, _Predicate __pred) + { return __c._M_erase_if(std::move(__pred)); } + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cpp_lib_flat_set diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 2e9319c..f64f35a 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -56,7 +56,7 @@ #include <bits/ranges_base.h> // input_range, range_reference_t #include <bits/ranges_util.h> // subrange #include <bits/ranges_algobase.h> // ranges::copy -#include <bits/stl_iterator.h> // back_insert_iterator +#include <bits/stl_iterator.h> // counted_iterator #include <bits/stl_pair.h> // __is_pair #include <bits/unicode.h> // __is_scalar_value, _Utf_view, etc. #include <bits/utility.h> // tuple_size_v @@ -80,12 +80,46 @@ _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; + template<typename _Out, typename _CharT> class _Escaping_sink; + // Output iterator that writes to a type-erase character sink. template<typename _CharT> class _Sink_iter; + // Output iterator that ignores the characters + template<typename _CharT> + class _Drop_iter; + + // An unspecified output iterator type used in the `formattable` concept. + template<typename _CharT> + struct _Iter_for + { using type = _Drop_iter<_CharT>; }; + template<typename _CharT> using __format_context = basic_format_context<_Sink_iter<_CharT>, _CharT>; @@ -104,6 +138,7 @@ namespace __format template<typename, typename...> friend struct std::basic_format_string; }; + } // namespace __format /// @endcond @@ -442,36 +477,33 @@ namespace __format return {0, nullptr}; } - enum _Pres_type { + enum class _Pres_type : unsigned char { _Pres_none = 0, // Default type (not valid for integer presentation types). + _Pres_s = 1, // For strings, bool, ranges // Presentation types for integral types (including bool and charT). - _Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c, - // Presentation types for floating-point types. - _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, _Pres_g, _Pres_G, - _Pres_p = 0, _Pres_P, // For pointers. - _Pres_s = 0, // For strings 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 +515,17 @@ namespace __format constexpr bool __is_xdigit(char __c) { return std::__detail::__from_chars_alnum_to_val(__c) < 16; } + // Used to make _Spec a non-C++98 POD, so the tail-padding is used. + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#pod + struct _SpecBase + { }; + template<typename _CharT> - struct _Spec + struct _Spec : _SpecBase { + unsigned short _M_width; + unsigned short _M_prec; + char32_t _M_fill = ' '; _Align _M_align : 2; _Sign _M_sign : 2; unsigned _M_alt : 1; @@ -493,12 +533,11 @@ namespace __format unsigned _M_zero_fill : 1; _WidthPrec _M_width_kind : 2; _WidthPrec _M_prec_kind : 2; + unsigned _M_debug : 1; _Pres_type _M_type : 4; - unsigned _M_reserved : 1; - unsigned _M_reserved2 : 16; - unsigned short _M_width; - unsigned short _M_prec; - char32_t _M_fill = ' '; + unsigned _M_reserved : 8; + // This class has 8 bits of tail padding, that can be used by + // derived classes. using iterator = typename basic_string_view<_CharT>::iterator; @@ -517,42 +556,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 +618,7 @@ namespace __format constexpr iterator _M_parse_sign(iterator __first, iterator) noexcept { - if (_Sign __sign = _S_sign(*__first)) + if (_Sign __sign = _S_sign(*__first); __sign != _Sign_default) { _M_sign = __sign; return __first + 1; @@ -800,7 +845,7 @@ namespace __format { // Encode fill char as multiple code units of type _CharT. const char32_t __arr[1]{ __fill_char }; - _Utf_view<_CharT, const char32_t(&)[1]> __v(__arr); + _Utf_view<_CharT, span<const char32_t, 1>> __v(__arr); basic_string<_CharT> __padstr(__v.begin(), __v.end()); __padding = __padstr; while (__l-- > 0) @@ -841,13 +886,362 @@ 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_escape_seqs(_Out __out, basic_string_view<_CharT> __units) + { + using _UChar = make_unsigned_t<_CharT>; + for (_CharT __c : __units) + __out = __format::__write_escape_seq( + __out, static_cast<_UChar>(__c), _Escapes<_CharT>::_S_x()); + return __out; + } + + template<typename _Out, typename _CharT> + _Out + __write_escaped_char(_Out __out, _CharT __c) + { + using _UChar = make_unsigned_t<_CharT>; + 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_part(_Out __out, basic_string_view<_CharT>& __str, + bool& __prev_esc, _Term_char __term) + { + using _Str_view = basic_string_view<_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)); + __str = {}; + + auto __first = __v.begin(); + auto const __last = __v.end(); + 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()); + // __esc_replace + else if (_Str_view __units(__first.base(), __first._M_units()); + __units.end() != __last.base()) + __out = __format::__write_escape_seqs(__out, __units); + else + { + __str = __units; + return __out; + } + + __prev_esc = true; + ++__first; + } + + return __out; + } + + template<typename _CharT, typename _Out> + _Out + __write_escaped_unicode(_Out __out, basic_string_view<_CharT> __str, + _Term_char __term) + { + bool __prev_escape = true; + __out = __format::__write_escaped_unicode_part(__out, __str, + __prev_escape, __term); + __out = __format::__write_escape_seqs(__out, __str); + return __out; + } + + 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 +1318,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 +1361,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 +1384,87 @@ 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_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>) { - if (_M_spec._M_prec_kind != _WP_none) - { - size_t __prec = _M_spec._M_get_precision(__fc); - __estimated_width = __unicode::__truncate(__s, __prec); - } - else - __estimated_width = __unicode::__field_width(__s); + _String_view __str(ranges::data(__rg), + size_t(ranges::distance(__rg))); + return format(__str, __fc); } else { - __s = __s.substr(0, _M_spec._M_get_precision(__fc)); - __estimated_width = __s.size(); + auto __handle_debug = [this, &__rg]<typename _NOut>(_NOut __nout) + { + if (!_M_spec._M_debug) + return ranges::copy(__rg, std::move(__nout)).out; + + _Escaping_sink<_NOut, _CharT> + __sink(std::move(__nout), _Term_quote); + ranges::copy(__rg, __sink.out()); + return __sink._M_finish(); + }; + + const size_t __padwidth = _M_spec._M_get_width(__fc); + if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none) + return __handle_debug(__fc.out()); + + _Padding_sink<_Out, _CharT> + __sink(__fc.out(), __padwidth, _M_spec._M_get_precision(__fc)); + __handle_debug(__sink.out()); + return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill); } - - return __format::__write_padded_as_spec(__s, __estimated_width, - __fc, _M_spec); } -#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 +1480,16 @@ namespace __format static constexpr _Pres_type _AsBool = _Pres_s; static constexpr _Pres_type _AsChar = _Pres_c; + __formatter_int() = default; + + constexpr + __formatter_int(_Spec<_CharT> __spec) noexcept + : _M_spec(__spec) + { + if (_M_spec._M_type == _Pres_none) + _M_spec._M_type = _Pres_d; + } + constexpr typename basic_format_parse_context<_CharT>::iterator _M_do_parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type) { @@ -1116,15 +1577,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 +1606,8 @@ namespace __format { auto __end = _M_do_parse(__pc, _AsBool); if (_M_spec._M_type == _Pres_s) - if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill) + if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt + || _M_spec._M_zero_fill) __throw_format_error("format error: format-spec contains " "invalid formatting options for " "'bool'"); @@ -1154,8 +1616,9 @@ namespace __format else if constexpr (__char<_Tp>) { auto __end = _M_do_parse(__pc, _AsChar); - if (_M_spec._M_type == _Pres_c || _M_spec._M_type == _Pres_esc) - if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill + if (_M_spec._M_type == _Pres_c) + if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt + || _M_spec._M_zero_fill /* XXX should be invalid? || _M_spec._M_localized */) __throw_format_error("format error: format-spec contains " "invalid formatting options for " @@ -1267,26 +1730,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> @@ -1385,37 +1857,27 @@ namespace __format __align, __nfill, __fill_char); } -#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ - template<typename _Tp> - using make_unsigned_t - = typename __conditional_t<(sizeof(_Tp) <= sizeof(long long)), - std::make_unsigned<_Tp>, - type_identity<unsigned __int128>>::type; - - // std::to_chars is not overloaded for int128 in strict mode. - template<typename _Int> - static to_chars_result - to_chars(char* __first, char* __last, _Int __value, int __base) - { return std::__to_chars_i<_Int>(__first, __last, __value, __base); } -#endif - _Spec<_CharT> _M_spec{}; }; +#ifdef __BFLT16_DIG__ + using __bflt16_t = decltype(0.0bf16); +#endif + // Decide how 128-bit floating-point types should be formatted (or not). - // When supported, the typedef __format::__float128_t is the type that - // format arguments should be converted to for storage in basic_format_arg. + // When supported, the typedef __format::__flt128_t is the type that format + // arguments should be converted to before passing them to __formatter_fp. // Define the macro _GLIBCXX_FORMAT_F128 to say they're supported. - // _GLIBCXX_FORMAT_F128=1 means __float128, _Float128 etc. will be formatted - // by converting them to long double (or __ieee128 for powerpc64le). - // _GLIBCXX_FORMAT_F128=2 means basic_format_arg needs to enable explicit - // support for _Float128, rather than formatting it as another type. + // The __float128, _Float128 will be formatted by converting them to: + // __ieee128 (same as __float128) when _GLIBCXX_FORMAT_F128=1, + // long double when _GLIBCXX_FORMAT_F128=2, + // _Float128 when _GLIBCXX_FORMAT_F128=3. #undef _GLIBCXX_FORMAT_F128 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // Format 128-bit floating-point types using __ieee128. - using __float128_t = __ieee128; + using __flt128_t = __ieee128; # define _GLIBCXX_FORMAT_F128 1 #ifdef __LONG_DOUBLE_IEEE128__ @@ -1449,14 +1911,14 @@ namespace __format #elif defined _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128 // Format 128-bit floating-point types using long double. - using __float128_t = long double; -# define _GLIBCXX_FORMAT_F128 1 + using __flt128_t = long double; +# define _GLIBCXX_FORMAT_F128 2 #elif __FLT128_DIG__ && defined(_GLIBCXX_HAVE_FLOAT128_MATH) // Format 128-bit floating-point types using _Float128. - using __float128_t = _Float128; -# define _GLIBCXX_FORMAT_F128 2 + using __flt128_t = _Float128; +# define _GLIBCXX_FORMAT_F128 3 # if __cplusplus == 202002L // These overloads exist in the library, but are not declared for C++20. @@ -1925,9 +2387,16 @@ namespace __format const size_t __r = __str.size() - __e; // Length of remainder. auto __overwrite = [&](_CharT* __p, size_t) { // Apply grouping to the digits before the radix or exponent. - auto __end = std::__add_grouping(__p, __np.thousands_sep(), + int __off = 0; + if (auto __c = __str.front(); __c == '-' || __c == '+' || __c == ' ') + { + *__p = __c; + __off = 1; + } + auto __end = std::__add_grouping(__p + __off, __np.thousands_sep(), __grp.data(), __grp.size(), - __str.data(), __str.data() + __e); + __str.data() + __off, + __str.data() + __e); if (__r) // If there's a fractional part or exponent { if (__d != __str.npos) @@ -1950,6 +2419,150 @@ namespace __format _Spec<_CharT> _M_spec{}; }; + template<__format::__char _CharT> + struct __formatter_ptr + { + __formatter_ptr() = default; + + constexpr + __formatter_ptr(_Spec<_CharT> __spec) noexcept + : _M_spec(__spec) + { _M_set_default(_Pres_p); } + + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type = _Pres_p) + { + __format::_Spec<_CharT> __spec{}; + const auto __last = __pc.end(); + auto __first = __pc.begin(); + + auto __finalize = [this, &__spec, __type] { + _M_spec = __spec; + _M_set_default(__type); + }; + + auto __finished = [&] { + if (__first == __last || *__first == '}') + { + __finalize(); + return true; + } + return false; + }; + + if (__finished()) + return __first; + + __first = __spec._M_parse_fill_and_align(__first, __last); + if (__finished()) + return __first; + +// _GLIBCXX_RESOLVE_LIB_DEFECTS +// P2510R3 Formatting pointers +#if __glibcxx_format >= 202304L + __first = __spec._M_parse_zero_fill(__first, __last); + if (__finished()) + return __first; +#endif + + __first = __spec._M_parse_width(__first, __last, __pc); + if (__finished()) + return __first; + + if (*__first == 'p') + { + __spec._M_type = _Pres_p; + _M_spec._M_alt = !_M_spec._M_alt; + ++__first; + } +#if __glibcxx_format >= 202304L + else if (*__first == 'P') + { + __spec._M_type = _Pres_P; + _M_spec._M_alt = !_M_spec._M_alt; + ++__first; + } +#endif + + if (__finished()) + return __first; + + __format::__failed_to_parse_format_spec(); + } + + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const + { + auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v); + char __buf[2 + sizeof(__v) * 2]; + auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf), + __u, 16); + int __n = __ptr - __buf; + __buf[0] = '0'; + __buf[1] = 'x'; +#if __glibcxx_format >= 202304L + if (_M_spec._M_type == __format::_Pres_P) + { + __buf[1] = 'X'; + for (auto __p = __buf + 2; __p != __ptr; ++__p) +#if __has_builtin(__builtin_toupper) + *__p = __builtin_toupper(*__p); +#else + *__p = std::toupper(*__p); +#endif + } +#endif + + basic_string_view<_CharT> __str; + if constexpr (is_same_v<_CharT, char>) + __str = string_view(__buf, __n); +#ifdef _GLIBCXX_USE_WCHAR_T + else + { + auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT)); + std::__to_wstring_numeric(__buf, __n, __p); + __str = wstring_view(__p, __n); + } +#endif + +#if __glibcxx_format >= 202304L + if (_M_spec._M_zero_fill) + { + size_t __width = _M_spec._M_get_width(__fc); + if (__width <= __str.size()) + return __format::__write(__fc.out(), __str); + + auto __out = __fc.out(); + // Write "0x" or "0X" prefix before zero-filling. + __out = __format::__write(std::move(__out), __str.substr(0, 2)); + __str.remove_prefix(2); + size_t __nfill = __width - __n; + return __format::__write_padded(std::move(__out), __str, + __format::_Align_right, + __nfill, _CharT('0')); + } +#endif + + return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec, + __format::_Align_right); + } + + private: + [[__gnu__::__always_inline__]] + constexpr void + _M_set_default(_Pres_type __type) + { + if (_M_spec._M_type == _Pres_none && __type != _Pres_none) + { + _M_spec._M_type = __type; + _M_spec._M_alt = !_M_spec._M_alt; + } + } + + __format::_Spec<_CharT> _M_spec{}; + }; + } // namespace __format /// @endcond @@ -1969,28 +2582,27 @@ 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: __format::__formatter_int<_CharT> _M_f; }; +#if __glibcxx_print >= 202403L + template<__format::__char _CharT> + constexpr bool enable_nonlocking_formatter_optimization<_CharT> = true; +#endif + #ifdef _GLIBCXX_USE_WCHAR_T /// Format a char value for wide character output. template<> @@ -2008,22 +2620,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 +2656,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 @@ -2058,6 +2664,11 @@ namespace __format __format::__formatter_str<_CharT> _M_f; }; +#if __glibcxx_print >= 202403L + template<__format::__char _CharT> + constexpr bool enable_nonlocking_formatter_optimization<_CharT*> = true; +#endif + template<__format::__char _CharT> struct formatter<const _CharT*, _CharT> { @@ -2075,7 +2686,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 @@ -2083,6 +2694,12 @@ namespace __format __format::__formatter_str<_CharT> _M_f; }; +#if __glibcxx_print >= 202403L + template<__format::__char _CharT> + constexpr bool + enable_nonlocking_formatter_optimization<const _CharT*> = true; +#endif + template<__format::__char _CharT, size_t _Nm> struct formatter<_CharT[_Nm], _CharT> { @@ -2099,7 +2716,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 @@ -2107,6 +2724,11 @@ namespace __format __format::__formatter_str<_CharT> _M_f; }; +#if __glibcxx_print >= 202403L + template<__format::__char _CharT, size_t _Nm> + constexpr bool enable_nonlocking_formatter_optimization<_CharT[_Nm]> = true; +#endif + template<typename _Traits, typename _Alloc> struct formatter<basic_string<char, _Traits, _Alloc>, char> { @@ -2123,7 +2745,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 @@ -2131,6 +2753,13 @@ namespace __format __format::__formatter_str<char> _M_f; }; +#if __glibcxx_print >= 202403L + template<typename _Tr, typename _Alloc> + constexpr bool + enable_nonlocking_formatter_optimization<basic_string<char, _Tr, _Alloc>> + = true; +#endif + #ifdef _GLIBCXX_USE_WCHAR_T template<typename _Traits, typename _Alloc> struct formatter<basic_string<wchar_t, _Traits, _Alloc>, wchar_t> @@ -2148,13 +2777,21 @@ 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 private: __format::__formatter_str<wchar_t> _M_f; }; + +#if __glibcxx_print >= 202403L + template<typename _Tr, typename _Alloc> + constexpr bool + enable_nonlocking_formatter_optimization<basic_string<wchar_t, _Tr, _Alloc>> + = true; +#endif + #endif // USE_WCHAR_T template<typename _Traits> @@ -2173,7 +2810,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 @@ -2181,6 +2818,13 @@ namespace __format __format::__formatter_str<char> _M_f; }; +#if __glibcxx_print >= 202403L + template<typename _Tr> + constexpr bool + enable_nonlocking_formatter_optimization<basic_string_view<char, _Tr>> + = true; +#endif + #ifdef _GLIBCXX_USE_WCHAR_T template<typename _Traits> struct formatter<basic_string_view<wchar_t, _Traits>, wchar_t> @@ -2198,13 +2842,20 @@ 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 private: __format::__formatter_str<wchar_t> _M_f; }; + +#if __glibcxx_print >= 202403L + template<typename _Tr> + constexpr bool + enable_nonlocking_formatter_optimization<basic_string_view<wchar_t, _Tr>> + = true; +#endif #endif // USE_WCHAR_T /// @} @@ -2229,12 +2880,14 @@ namespace __format #endif template<> inline constexpr bool __is_formattable_integer<char16_t> = false; template<> inline constexpr bool __is_formattable_integer<char32_t> = false; + + template<typename _Tp> + concept __formattable_integer = __is_formattable_integer<_Tp>; } /// @endcond /// Format an integer. - template<typename _Tp, __format::__char _CharT> - requires __format::__is_formattable_integer<_Tp> + template<__format::__formattable_integer _Tp, __format::__char _CharT> struct formatter<_Tp, _CharT> { formatter() = default; @@ -2255,6 +2908,12 @@ namespace __format __format::__formatter_int<_CharT> _M_f; }; +#if __glibcxx_print >= 202403L + template<__format::__formattable_integer _Tp> + constexpr bool + enable_nonlocking_formatter_optimization<_Tp> = true; +#endif + #if defined __glibcxx_to_chars /// Format a floating-point value. template<__format::__formattable_float _Tp, __format::__char _CharT> @@ -2276,6 +2935,12 @@ namespace __format __format::__formatter_fp<_CharT> _M_f; }; +#if __glibcxx_print >= 202403L + template<__format::__formattable_float _Tp> + constexpr bool + enable_nonlocking_formatter_optimization<_Tp> = true; +#endif + #if __LDBL_MANT_DIG__ == __DBL_MANT_DIG__ // Reuse __formatter_fp<C>::format<double, Out> for long double. template<__format::__char _CharT> @@ -2364,8 +3029,8 @@ namespace __format }; #endif -#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 == 1 - // Reuse __formatter_fp<C>::format<__float128_t, Out> for _Float128. +#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 + // Use __formatter_fp<C>::format<__format::__flt128_t, Out> for _Float128. template<__format::__char _CharT> struct formatter<_Float128, _CharT> { @@ -2379,7 +3044,30 @@ namespace __format template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(_Float128 __u, basic_format_context<_Out, _CharT>& __fc) const - { return _M_f.format((__format::__float128_t)__u, __fc); } + { return _M_f.format((__format::__flt128_t)__u, __fc); } + + private: + __format::__formatter_fp<_CharT> _M_f; + }; +#endif + +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 == 2 + // Use __formatter_fp<C>::format<__format::__flt128_t, Out> for __float128, + // when long double is not 128bit IEEE type. + template<__format::__char _CharT> + struct formatter<__float128, _CharT> + { + formatter() = default; + + [[__gnu__::__always_inline__]] + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__float128 __u, basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format((__format::__flt128_t)__u, __fc); } private: __format::__formatter_fp<_CharT> _M_f; @@ -2389,7 +3077,7 @@ namespace __format #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) // Reuse __formatter_fp<C>::format<float, Out> for bfloat16_t. template<__format::__char _CharT> - struct formatter<__gnu_cxx::__bfloat16_t, _CharT> + struct formatter<__format::__bflt16_t, _CharT> { formatter() = default; @@ -2420,122 +3108,23 @@ namespace __format constexpr typename basic_format_parse_context<_CharT>::iterator parse(basic_format_parse_context<_CharT>& __pc) - { - __format::_Spec<_CharT> __spec{}; - const auto __last = __pc.end(); - auto __first = __pc.begin(); - - auto __finalize = [this, &__spec] { - _M_spec = __spec; - }; - - auto __finished = [&] { - if (__first == __last || *__first == '}') - { - __finalize(); - return true; - } - return false; - }; - - if (__finished()) - return __first; - - __first = __spec._M_parse_fill_and_align(__first, __last); - if (__finished()) - return __first; - -// _GLIBCXX_RESOLVE_LIB_DEFECTS -// P2510R3 Formatting pointers -#if __glibcxx_format >= 202304L - __first = __spec._M_parse_zero_fill(__first, __last); - if (__finished()) - return __first; -#endif - - __first = __spec._M_parse_width(__first, __last, __pc); - - if (__first != __last) - { - if (*__first == 'p') - ++__first; -#if __glibcxx_format >= 202304L - else if (*__first == 'P') - { - __spec._M_type = __format::_Pres_P; - ++__first; - } -#endif - } - - if (__finished()) - return __first; - - __format::__failed_to_parse_format_spec(); - } + { return _M_f.parse(__pc); } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const - { - auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v); - char __buf[2 + sizeof(__v) * 2]; - auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf), - __u, 16); - int __n = __ptr - __buf; - __buf[0] = '0'; - __buf[1] = 'x'; -#if __glibcxx_format >= 202304L - if (_M_spec._M_type == __format::_Pres_P) - { - __buf[1] = 'X'; - for (auto __p = __buf + 2; __p != __ptr; ++__p) -#if __has_builtin(__builtin_toupper) - *__p = __builtin_toupper(*__p); -#else - *__p = std::toupper(*__p); -#endif - } -#endif - - basic_string_view<_CharT> __str; - if constexpr (is_same_v<_CharT, char>) - __str = string_view(__buf, __n); -#ifdef _GLIBCXX_USE_WCHAR_T - else - { - auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT)); - std::__to_wstring_numeric(__buf, __n, __p); - __str = wstring_view(__p, __n); - } -#endif - -#if __glibcxx_format >= 202304L - if (_M_spec._M_zero_fill) - { - size_t __width = _M_spec._M_get_width(__fc); - if (__width <= __str.size()) - return __format::__write(__fc.out(), __str); - - auto __out = __fc.out(); - // Write "0x" or "0X" prefix before zero-filling. - __out = __format::__write(std::move(__out), __str.substr(0, 2)); - __str.remove_prefix(2); - size_t __nfill = __width - __n; - return __format::__write_padded(std::move(__out), __str, - __format::_Align_right, - __nfill, _CharT('0')); - } -#endif - - return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec, - __format::_Align_right); - } + { return _M_f.format(__v, __fc); } private: - __format::_Spec<_CharT> _M_spec{}; + __format::__formatter_ptr<_CharT> _M_f; }; +#if __glibcxx_print >= 202403L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization<const void*> = true; +#endif + template<__format::__char _CharT> struct formatter<void*, _CharT> { @@ -2552,9 +3141,15 @@ namespace __format { return _M_f.format(__v, __fc); } private: - formatter<const void*, _CharT> _M_f; + __format::__formatter_ptr<_CharT> _M_f; }; +#if __glibcxx_print >= 202403l + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization<void*> = true; +#endif + template<__format::__char _CharT> struct formatter<nullptr_t, _CharT> { @@ -2571,98 +3166,44 @@ 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 __glibcxx_print >= 202403L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization<nullptr_t> = true; +#endif + +#if defined _GLIBCXX_USE_WCHAR_T && __glibcxx_format_ranges // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3944. Formatters converting sequences of char to sequences of wchar_t - namespace __format { struct __disabled; } + struct __formatter_disabled + { + __formatter_disabled() = delete; // Cannot format char sequence to wchar_t + __formatter_disabled(const __formatter_disabled&) = delete; + __formatter_disabled& operator=(const __formatter_disabled&) = delete; + }; - // std::formatter<__disabled, C> uses the primary template, which is disabled. template<> struct formatter<char*, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<> struct formatter<const char*, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<size_t _Nm> struct formatter<char[_Nm], wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<class _Traits, class _Allocator> struct formatter<basic_string<char, _Traits, _Allocator>, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<class _Traits> struct formatter<basic_string_view<char, _Traits>, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; #endif -/// @cond undocumented -namespace __format -{ - template<typename _Tp, typename _Context, - typename _Formatter - = typename _Context::template formatter_type<remove_const_t<_Tp>>, - typename _ParseContext - = basic_format_parse_context<typename _Context::char_type>> - concept __parsable_with - = semiregular<_Formatter> - && requires (_Formatter __f, _ParseContext __pc) - { - { __f.parse(__pc) } -> same_as<typename _ParseContext::iterator>; - }; - - template<typename _Tp, typename _Context, - typename _Formatter - = typename _Context::template formatter_type<remove_const_t<_Tp>>, - typename _ParseContext - = basic_format_parse_context<typename _Context::char_type>> - concept __formattable_with - = semiregular<_Formatter> - && requires (const _Formatter __cf, _Tp&& __t, _Context __fc) - { - { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>; - }; - - // An unspecified output iterator type used in the `formattable` concept. - template<typename _CharT> - using _Iter_for = back_insert_iterator<basic_string<_CharT>>; - - template<typename _Tp, typename _CharT, - typename _Context = basic_format_context<_Iter_for<_CharT>, _CharT>> - concept __formattable_impl - = __parsable_with<_Tp, _Context> && __formattable_with<_Tp, _Context>; - -} // 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>; -#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> @@ -2680,6 +3221,43 @@ _GLIBCXX_END_NAMESPACE_CONTAINER namespace __format { template<typename _CharT> + class _Drop_iter + { + public: + using iterator_category = output_iterator_tag; + using value_type = void; + using difference_type = ptrdiff_t; + using pointer = void; + using reference = void; + + _Drop_iter() = default; + _Drop_iter(const _Drop_iter&) = default; + _Drop_iter& operator=(const _Drop_iter&) = default; + + [[__gnu__::__always_inline__]] + constexpr _Drop_iter& + operator=(_CharT __c) + { return *this; } + + [[__gnu__::__always_inline__]] + constexpr _Drop_iter& + operator=(basic_string_view<_CharT> __s) + { return *this; } + + [[__gnu__::__always_inline__]] + constexpr _Drop_iter& + operator*() { return *this; } + + [[__gnu__::__always_inline__]] + constexpr _Drop_iter& + operator++() { return *this; } + + [[__gnu__::__always_inline__]] + constexpr _Drop_iter + operator++(int) { return *this; } + }; + + template<typename _CharT> class _Sink_iter { _Sink<_CharT>* _M_sink = nullptr; @@ -2730,6 +3308,10 @@ namespace __format auto _M_reserve(size_t __n) const { return _M_sink->_M_reserve(__n); } + + bool + _M_discarding() const + { return _M_sink->_M_discarding(); } }; // Abstract base class for type-erased character sinks. @@ -2849,6 +3431,11 @@ namespace __format _M_bump(size_t __n) { _M_next += __n; } + // Returns true if the _Sink is discarding incoming characters. + virtual bool + _M_discarding() const + { return false; } + public: _Sink(const _Sink&) = delete; _Sink& operator=(const _Sink&) = delete; @@ -2859,12 +3446,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 +3491,12 @@ namespace __format // A sink that fills a sequence (e.g. std::string, std::vector, std::deque). // Writes to a buffer then appends that to the sequence when it fills up. template<typename _Seq> - class _Seq_sink final : public _Buf_sink<typename _Seq::value_type> + class _Seq_sink : public _Buf_sink<typename _Seq::value_type> { using _CharT = typename _Seq::value_type; _Seq _M_seq; - + protected: // Transfer buffer contents to the sequence, so buffer can be refilled. void _M_overflow() override @@ -2955,6 +3568,17 @@ namespace __format } } + void _M_trim(span<const _CharT> __s) + requires __is_specialization_of<_Seq, basic_string> + { + _GLIBCXX_DEBUG_ASSERT(__s.data() == this->_M_buf + || __s.data() == _M_seq.data()); + if (__s.data() == _M_seq.data()) + _M_seq.resize(__s.size()); + else + this->_M_reset(this->_M_buf, __s.size()); + } + public: // TODO: for SSO string, use SSO buffer as initial span, then switch // to _M_buf if it overflows? Or even do that for all unused capacity? @@ -2980,7 +3604,7 @@ namespace __format // A writable span that views everything written to the sink. // Will be either a view over _M_seq or the used part of _M_buf. span<_CharT> - view() + _M_span() { auto __s = this->_M_used(); if (_M_seq.size()) @@ -2991,6 +3615,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 +3629,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 +3661,14 @@ namespace __format _M_count += __s.size(); } + bool + _M_discarding() const override + { + // format_to_n return total number of characters, that would be written, + // see C++20 [format.functions] p20 + return false; + } + public: [[__gnu__::__always_inline__]] explicit @@ -3094,6 +3731,14 @@ namespace __format } } + bool + _M_discarding() const override + { + // format_to_n return total number of characters, that would be written, + // see C++20 [format.functions] p20 + return false; + } + typename _Sink<_CharT>::_Reservation _M_reserve(size_t __n) final { @@ -3168,20 +3813,289 @@ namespace __format } }; - enum _Arg_t : unsigned char { + // A sink for handling the padded outputs (_M_padwidth) or truncated + // (_M_maxwidth). The handling is done by writting to buffer (_Str_strink) + // until sufficient number of characters is written. After that if sequence + // is longer than _M_padwidth it's written to _M_out, and further writes are + // either: + // * buffered and forwarded to _M_out, if below _M_maxwidth, + // * ignored otherwise + // If field width of written sequence is no greater than _M_padwidth, the + // sequence is written during _M_finish call. + template<typename _Out, typename _CharT> + class _Padding_sink : public _Str_sink<_CharT> + { + size_t _M_padwidth; + size_t _M_maxwidth; + _Out _M_out; + size_t _M_printwidth; + + [[__gnu__::__always_inline__]] + bool + _M_ignoring() const + { return _M_printwidth >= _M_maxwidth; } + + [[__gnu__::__always_inline__]] + bool + _M_buffering() const + { + if (_M_printwidth < _M_padwidth) + return true; + if (_M_maxwidth != (size_t)-1) + return _M_printwidth < _M_maxwidth; + return false; + } + + void + _M_sync_discarding() + { + if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>) + if (_M_out._M_discarding()) + _M_maxwidth = _M_printwidth; + } + + void + _M_flush() + { + span<_CharT> __new = this->_M_used(); + basic_string_view<_CharT> __str(__new.data(), __new.size()); + _M_out = __format::__write(std::move(_M_out), __str); + _M_sync_discarding(); + this->_M_rewind(); + } + + bool + _M_force_update() + { + auto __str = this->view(); + // Compute actual field width, possibly truncated. + _M_printwidth = __format::__truncate(__str, _M_maxwidth); + if (_M_ignoring()) + this->_M_trim(__str); + if (_M_buffering()) + return true; + + // We have more characters than padidng, no padding is needed, + // write direclty to _M_out. + if (_M_printwidth >= _M_padwidth) + { + _M_out = __format::__write(std::move(_M_out), __str); + _M_sync_discarding(); + } + // We reached _M_maxwidth that is smaller than _M_padwidth. + // Store the prefix sequence in _M_seq, and free _M_buf. + else + _Str_sink<_CharT>::_M_overflow(); + + // Use internal buffer for writes to _M_out. + this->_M_reset(this->_M_buf); + return false; + } + + bool + _M_update(size_t __new) + { + _M_printwidth += __new; + // Compute estimated width, to see if is not reduced. + if (_M_printwidth >= _M_padwidth || _M_printwidth >= _M_maxwidth) + return _M_force_update(); + return true; + } + + void + _M_overflow() override + { + // Ignore characters in buffer, and override it. + if (_M_ignoring()) + this->_M_rewind(); + // Write buffer to _M_out, and override it. + else if (!_M_buffering()) + _M_flush(); + // Update written count, and if input still should be buffered, + // flush the to _M_seq. + else if (_M_update(this->_M_used().size())) + _Str_sink<_CharT>::_M_overflow(); + } + + bool + _M_discarding() const override + { return _M_ignoring(); } + + typename _Sink<_CharT>::_Reservation + _M_reserve(size_t __n) override + { + // Ignore characters in buffer, if any. + if (_M_ignoring()) + this->_M_rewind(); + else if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>) + if (!_M_buffering()) + { + // Write pending characters if any + if (!this->_M_used().empty()) + _M_flush(); + // Try to reserve from _M_out sink. + if (auto __reserved = _M_out._M_reserve(__n)) + return __reserved; + } + return _Sink<_CharT>::_M_reserve(__n); + } + + void + _M_bump(size_t __n) override + { + // Ignore the written characters. + if (_M_ignoring()) + return; + // If reservation was made directy sink associated _M_out, + // _M_bump will be called on that sink. + _Sink<_CharT>::_M_bump(__n); + if (_M_buffering()) + _M_update(__n); + } + + public: + [[__gnu__::__always_inline__]] + explicit + _Padding_sink(_Out __out, size_t __padwidth, size_t __maxwidth) + : _M_padwidth(__padwidth), _M_maxwidth(__maxwidth), + _M_out(std::move(__out)), _M_printwidth(0) + { _M_sync_discarding(); } + + [[__gnu__::__always_inline__]] + explicit + _Padding_sink(_Out __out, size_t __padwidth) + : _Padding_sink(std::move(__out), __padwidth, (size_t)-1) + { } + + _Out + _M_finish(_Align __align, char32_t __fill_char) + { + // Handle any characters in the buffer. + if (auto __rem = this->_M_used().size()) + { + if (_M_ignoring()) + this->_M_rewind(); + else if (!_M_buffering()) + _M_flush(); + else + _M_update(__rem); + } + + if (!_M_buffering() || !_M_force_update()) + // Characters were already written to _M_out. + if (_M_printwidth >= _M_padwidth) + return std::move(_M_out); + + const auto __str = this->view(); + if (_M_printwidth >= _M_padwidth) + return __format::__write(std::move(_M_out), __str); + + const size_t __nfill = _M_padwidth - _M_printwidth; + return __format::__write_padded(std::move(_M_out), __str, + __align, __nfill, __fill_char); + } + }; + + template<typename _Out, typename _CharT> + class _Escaping_sink : public _Buf_sink<_CharT> + { + using _Esc = _Escapes<_CharT>; + + _Out _M_out; + _Term_char _M_term : 2; + unsigned _M_prev_escape : 1; + unsigned _M_out_discards : 1; + + void + _M_sync_discarding() + { + if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>) + _M_out_discards = _M_out._M_discarding(); + } + + void + _M_write() + { + span<_CharT> __bytes = this->_M_used(); + basic_string_view<_CharT> __str(__bytes.data(), __bytes.size()); + + size_t __rem = 0; + if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>()) + { + bool __prev_escape = _M_prev_escape; + _M_out = __format::__write_escaped_unicode_part( + std::move(_M_out), __str, __prev_escape, _M_term); + _M_prev_escape = __prev_escape; + + __rem = __str.size(); + if (__rem > 0 && __str.data() != this->_M_buf) [[unlikely]] + ranges::move(__str, this->_M_buf); + } + else + _M_out = __format::__write_escaped_ascii( + std::move(_M_out), __str, _M_term); + + this->_M_reset(this->_M_buf, __rem); + _M_sync_discarding(); + } + + void + _M_overflow() override + { + if (_M_out_discards) + this->_M_rewind(); + else + _M_write(); + } + + bool + _M_discarding() const override + { return _M_out_discards; } + + public: + [[__gnu__::__always_inline__]] + explicit + _Escaping_sink(_Out __out, _Term_char __term) + : _M_out(std::move(__out)), _M_term(__term), + _M_prev_escape(true), _M_out_discards(false) + { + _M_out = __format::__write(std::move(_M_out), _Esc::_S_term(_M_term)); + _M_sync_discarding(); + } + + _Out + _M_finish() + { + if (_M_out_discards) + return std::move(_M_out); + + if (!this->_M_used().empty()) + { + _M_write(); + if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>()) + if (auto __rem = this->_M_used(); !__rem.empty()) + { + basic_string_view<_CharT> __str(__rem.data(), __rem.size()); + _M_out = __format::__write_escape_seqs(std::move(_M_out), __str); + } + } + return __format::__write(std::move(_M_out), _Esc::_S_term(_M_term)); + } + }; + + enum class _Arg_t : unsigned char { _Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull, _Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle, - _Arg_i128, _Arg_u128, - _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, // These are unused. + _Arg_i128, _Arg_u128, _Arg_float128, + _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, + _Arg_max_, + #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT - _Arg_next_value_, - _Arg_f128 = _Arg_ldbl, - _Arg_ibm128 = _Arg_next_value_, -#else - _Arg_f128, + _Arg_ibm128 = _Arg_ldbl, + _Arg_ieee128 = _Arg_float128, #endif - _Arg_max_ }; + using enum _Arg_t; template<typename _Context> struct _Arg_value @@ -3207,6 +4121,12 @@ namespace __format double _M_dbl; #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // No long double if it's ambiguous. long double _M_ldbl; +#else + __ibm128 _M_ibm128; + __ieee128 _M_ieee128; +#endif +#ifdef __SIZEOF_FLOAT128__ + __float128 _M_float128; #endif const _CharT* _M_str; basic_string_view<_CharT> _M_sv; @@ -3216,11 +4136,17 @@ namespace __format __int128 _M_i128; unsigned __int128 _M_u128; #endif -#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT - __ieee128 _M_f128; - __ibm128 _M_ibm128; -#elif _GLIBCXX_FORMAT_F128 == 2 - __float128_t _M_f128; +#ifdef __BFLT16_DIG__ + __bflt16_t _M_bf16; +#endif +#ifdef __FLT16_DIG__ + _Float16 _M_f16; +#endif +#ifdef __FLT32_DIG__ + _Float32 _M_f32; +#endif +#ifdef __FLT64_DIG__ + _Float64 _M_f64; #endif }; @@ -3258,10 +4184,14 @@ namespace __format else if constexpr (is_same_v<_Tp, long double>) return __u._M_ldbl; #else - else if constexpr (is_same_v<_Tp, __ieee128>) - return __u._M_f128; else if constexpr (is_same_v<_Tp, __ibm128>) return __u._M_ibm128; + else if constexpr (is_same_v<_Tp, __ieee128>) + return __u._M_ieee128; +#endif +#ifdef __SIZEOF_FLOAT128__ + else if constexpr (is_same_v<_Tp, __float128>) + return __u._M_float128; #endif else if constexpr (is_same_v<_Tp, const _CharT*>) return __u._M_str; @@ -3275,9 +4205,21 @@ namespace __format else if constexpr (is_same_v<_Tp, unsigned __int128>) return __u._M_u128; #endif -#if _GLIBCXX_FORMAT_F128 == 2 - else if constexpr (is_same_v<_Tp, __float128_t>) - return __u._M_f128; +#ifdef __BFLT16_DIG__ + else if constexpr (is_same_v<_Tp, __bflt16_t>) + return __u._M_bf16; +#endif +#ifdef __FLT16_DIG__ + else if constexpr (is_same_v<_Tp, _Float16>) + return __u._M_f16; +#endif +#ifdef __FLT32_DIG__ + else if constexpr (is_same_v<_Tp, _Float32>) + return __u._M_f32; +#endif +#ifdef __FLT64_DIG__ + else if constexpr (is_same_v<_Tp, _Float64>) + return __u._M_f64; #endif else if constexpr (derived_from<_Tp, _HandleBase>) return static_cast<_Tp&>(__u._M_handle); @@ -3456,36 +4398,25 @@ namespace __format else if constexpr (is_same_v<_Td, __ieee128>) return type_identity<__ieee128>(); #endif - -#if defined(__FLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) - else if constexpr (is_same_v<_Td, _Float16>) - return type_identity<float>(); +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 + else if constexpr (is_same_v<_Td, __float128>) + return type_identity<__float128>(); #endif - -#if defined(__BFLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) - else if constexpr (is_same_v<_Td, decltype(0.0bf16)>) - return type_identity<float>(); +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Td, __format::__bflt16_t>) + return type_identity<__format::__bflt16_t>(); +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Td, _Float16>) + return type_identity<_Float16>(); #endif - #if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) else if constexpr (is_same_v<_Td, _Float32>) - return type_identity<float>(); + return type_identity<_Float32>(); #endif - #if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) else if constexpr (is_same_v<_Td, _Float64>) - return type_identity<double>(); -#endif - -#if _GLIBCXX_FORMAT_F128 -# if __FLT128_DIG__ - else if constexpr (is_same_v<_Td, _Float128>) - return type_identity<__format::__float128_t>(); -# endif -# if __SIZEOF_FLOAT128__ - else if constexpr (is_same_v<_Td, __float128>) - return type_identity<__format::__float128_t>(); -# endif + return type_identity<_Float64>(); #endif else if constexpr (__is_specialization_of<_Td, basic_string_view> || __is_specialization_of<_Td, basic_string>) @@ -3541,7 +4472,27 @@ namespace __format else if constexpr (is_same_v<_Tp, __ibm128>) return _Arg_ibm128; else if constexpr (is_same_v<_Tp, __ieee128>) - return _Arg_f128; + return _Arg_ieee128; +#endif +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 + else if constexpr (is_same_v<_Tp, __float128>) + return _Arg_float128; +#endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Tp, __format::__bflt16_t>) + return _Arg_bf16; +#endif +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Tp, _Float16>) + return _Arg_f16; +#endif +#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + else if constexpr (is_same_v<_Tp, _Float32>) + return _Arg_f32; +#endif +#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + else if constexpr (is_same_v<_Tp, _Float64>) + return _Arg_f64; #endif else if constexpr (is_same_v<_Tp, const _CharT*>) return _Arg_str; @@ -3555,11 +4506,6 @@ namespace __format else if constexpr (is_same_v<_Tp, unsigned __int128>) return _Arg_u128; #endif - -#if _GLIBCXX_FORMAT_F128 == 2 - else if constexpr (is_same_v<_Tp, __format::__float128_t>) - return _Arg_f128; -#endif else if constexpr (is_same_v<_Tp, handle>) return _Arg_handle; } @@ -3632,13 +4578,33 @@ namespace __format #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT case _Arg_ldbl: return std::forward<_Visitor>(__vis)(_M_val._M_ldbl); +#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 + case _Arg_float128: + return std::forward<_Visitor>(__vis)(_M_val._M_float128); +#endif #else - case _Arg_f128: - return std::forward<_Visitor>(__vis)(_M_val._M_f128); case _Arg_ibm128: return std::forward<_Visitor>(__vis)(_M_val._M_ibm128); + case _Arg_ieee128: + return std::forward<_Visitor>(__vis)(_M_val._M_ieee128); #endif +#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + case _Arg_bf16: + return std::forward<_Visitor>(__vis)(_M_val._M_bf16); #endif +#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + case _Arg_f16: + return std::forward<_Visitor>(__vis)(_M_val._M_f16); +#endif +#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) + case _Arg_f32: + return std::forward<_Visitor>(__vis)(_M_val._M_f32); +#endif +#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) + case _Arg_f64: + return std::forward<_Visitor>(__vis)(_M_val._M_f64); +#endif +#endif // __glibcxx_to_chars case _Arg_str: return std::forward<_Visitor>(__vis)(_M_val._M_str); case _Arg_sv: @@ -3656,14 +4622,7 @@ namespace __format case _Arg_u128: return std::forward<_Visitor>(__vis)(_M_val._M_u128); #endif - -#if _GLIBCXX_FORMAT_F128 == 2 - case _Arg_f128: - return std::forward<_Visitor>(__vis)(_M_val._M_f128); -#endif - default: - // _Arg_f16 etc. __builtin_unreachable(); } } @@ -3675,17 +4634,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 +4708,7 @@ namespace __format { __UINT64_TYPE__ __packed_types = 0; for (auto __i = __types.rbegin(); __i != __types.rend(); ++__i) - __packed_types = (__packed_types << _Bits) | *__i; + __packed_types = (__packed_types << _Bits) | (unsigned)*__i; return __packed_types; } } // namespace __format @@ -3762,7 +4721,7 @@ namespace __format static constexpr int _S_packed_type_mask = 0b11111; static constexpr int _S_max_packed_args = 12; - static_assert( __format::_Arg_max_ <= (1 << _S_packed_type_bits) ); + static_assert( (unsigned)__format::_Arg_max_ <= (1u << _S_packed_type_bits) ); template<typename... _Args> using _Store = __format::_Arg_store<_Context, _Args...>; @@ -4713,22 +5672,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 +5703,599 @@ 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) + { + if constexpr (is_same_v<_Out, _Drop_iter<_CharT>>) + return __fc.out(); + else + { + // This is required to implement formatting with padding, + // as we need to format to temporary buffer, using the same iterator. + static_assert(is_same_v<_Out, _Sink_iter<_CharT>>); + + const size_t __padwidth = __spec._M_get_width(__fc); + if (__padwidth == 0) + return __call(__fc); + + struct _Restore_out + { + _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>& __fc) + : _M_ctx(std::addressof(__fc)), _M_out(__fc.out()) + { } + + void + _M_disarm() + { _M_ctx = nullptr; } + + ~_Restore_out() + { + if (_M_ctx) + _M_ctx->advance_to(_M_out); + } + + 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); } + }; + +#if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4399. enable_nonlocking_formatter_optimization for pair and tuple needs remove_cvref_t + template<typename _Fp, typename _Sp> + constexpr bool enable_nonlocking_formatter_optimization<pair<_Fp, _Sp>> + = enable_nonlocking_formatter_optimization<remove_cvref_t<_Fp>> + && enable_nonlocking_formatter_optimization<remove_cvref_t<_Sp>>; +#endif + + template<__format::__char _CharT, formattable<_CharT>... _Tps> + struct formatter<tuple<_Tps...>, _CharT> + : __format::__tuple_formatter<_CharT, remove_cvref_t<_Tps>...> + { + 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); } + }; + +#if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4399. enable_nonlocking_formatter_optimization for pair and tuple needs remove_cvref_t + template<typename... _Tps> + constexpr bool enable_nonlocking_formatter_optimization<tuple<_Tps...>> + = (enable_nonlocking_formatter_optimization<remove_cvref_t<_Tps>> && ...); +#endif + + // [format.range.formatter], class template range_formatter + template<typename _Tp, __format::__char _CharT> + 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 (format_kind<_Rg> == range_format::sequence) + { _M_under.set_separator(__sep); } + + constexpr void + set_brackets(basic_string_view<_CharT> __open, + basic_string_view<_CharT> __close) noexcept + requires (format_kind<_Rg> == range_format::sequence) + { _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; + }; + +#if __glibcxx_print >= 202406L + template<ranges::input_range _Rg> + requires (format_kind<_Rg> != range_format::disabled) + constexpr bool enable_nonlocking_formatter_optimization<_Rg> = false; +#endif + #endif // C++23 formatting ranges +#undef _GLIBCXX_WIDEN _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..570e9e9 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -52,8 +52,23 @@ #if __cplusplus >= 201103L +#define __glibcxx_want_boyer_moore_searcher +#define __glibcxx_want_bind_front +#define __glibcxx_want_bind_back +#define __glibcxx_want_constexpr_functional +#define __glibcxx_want_copyable_function +#define __glibcxx_want_function_ref +#define __glibcxx_want_invoke +#define __glibcxx_want_invoke_r +#define __glibcxx_want_move_only_function +#define __glibcxx_want_not_fn +#define __glibcxx_want_ranges +#define __glibcxx_want_reference_wrapper +#define __glibcxx_want_common_reference_wrapper +#define __glibcxx_want_transparent_operators +#include <bits/version.h> + #include <tuple> -#include <type_traits> #include <bits/functional_hash.h> #include <bits/invoke.h> #include <bits/refwrap.h> // std::reference_wrapper and _Mem_fn_traits @@ -69,26 +84,15 @@ # include <bits/stl_algobase.h> // std::search #endif #if __cplusplus >= 202002L +# include <bits/binders.h> # include <bits/ranges_cmp.h> // std::identity, ranges::equal_to etc. # include <compare> #endif -#if __cplusplus > 202002L && _GLIBCXX_HOSTED -# include <bits/move_only_function.h> +#if __glibcxx_move_only_function || __glibcxx_copyable_function || \ + __glibcxx_function_ref +# include <bits/funcwrap.h> #endif -#define __glibcxx_want_boyer_moore_searcher -#define __glibcxx_want_bind_front -#define __glibcxx_want_bind_back -#define __glibcxx_want_constexpr_functional -#define __glibcxx_want_invoke -#define __glibcxx_want_invoke_r -#define __glibcxx_want_move_only_function -#define __glibcxx_want_not_fn -#define __glibcxx_want_ranges -#define __glibcxx_want_reference_wrapper -#define __glibcxx_want_transparent_operators -#include <bits/version.h> - #endif // C++11 namespace std _GLIBCXX_VISIBILITY(default) @@ -492,6 +496,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION # define _GLIBCXX_DEPR_BIND #endif +#if _GLIBCXX_EXPLICIT_THIS_PARAMETER + // Return a _Up that has the same cv-quals as _Tp. + template<typename _Tp, typename _Up> // _Up should be cv-unqualified + struct __cv_like + { using type = _Up; }; + + template<typename _Tp, typename _Up> + struct __cv_like<const _Tp, _Up> + { using type = const _Up; }; + + template<typename _Tp, typename _Up> + struct __cv_like<volatile _Tp, _Up> + { using type = volatile _Up; }; + + template<typename _Tp, typename _Up> + struct __cv_like<const volatile _Tp, _Up> + { using type = const volatile _Up; }; + + template<typename _Tp, typename _Up> + using __cv_like_t = typename __cv_like<_Tp, _Up>::type; +#endif + /// Type of the function object returned from bind(). template<typename _Signature> class _Bind; @@ -561,6 +587,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Res_type_impl = __invoke_result_t<_Fn&, _Mu_type<_BArgs, _CallArgs>&&...>; +#if !_GLIBCXX_EXPLICIT_THIS_PARAMETER template<typename _CallArgs> using _Res_type = _Res_type_impl<_Functor, _CallArgs, _Bound_args...>; @@ -573,6 +600,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename __cv_quals<__dependent<_CallArgs>>::type, _CallArgs, typename __cv_quals<_Bound_args>::type...>; +#endif public: template<typename... _Args> @@ -590,6 +618,63 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Bind(const _Bind&) = default; _Bind(_Bind&&) = default; +#if _GLIBCXX_EXPLICIT_THIS_PARAMETER +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr +# pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this + template<typename... _Args, + typename _Self, + typename _Self_nonref = typename remove_reference<_Self>::type, + __enable_if_t<!is_volatile<_Self_nonref>::value, int> = 0, + typename _Result + = _Res_type_impl<__cv_like_t<_Self_nonref, _Functor>, + tuple<_Args...>, + __cv_like_t<_Self_nonref, _Bound_args>...>> + _GLIBCXX20_CONSTEXPR + _Result + operator()(this _Self&& __self, _Args&&... __args) + { + using _Bind_ref = __cv_like_t<_Self_nonref, _Bind>&; + if constexpr (is_const<_Self_nonref>::value) + return _Bind_ref(__self) + .template __call_c<_Result>(std::forward_as_tuple + (std::forward<_Args>(__args)...), + _Bound_indexes()); + else + return _Bind_ref(__self) + .template __call<_Result>(std::forward_as_tuple + (std::forward<_Args>(__args)...), + _Bound_indexes()); + } + +# if defined(_GLIBCXX_VOLATILE_BIND) + template<typename... _Args, + typename _Self, + typename _Self_nonref = typename remove_reference<_Self>::type, + __enable_if_t<is_volatile<_Self_nonref>::value, int> = 0, + typename _Result + = _Res_type_impl<__cv_like_t<_Self_nonref, _Functor>, + tuple<_Args...>, + __cv_like_t<_Self_nonref, _Bound_args>...>> + _GLIBCXX_DEPR_BIND + _Result + operator()(this _Self&& __self, _Args&&... __args) + { + using _Bind_ref = __cv_like_t<_Self_nonref, _Bind>&; + if constexpr (is_const<_Self_nonref>::value) + return _Bind_ref(__self) + .template __call_c_v<_Result>(std::forward_as_tuple + (std::forward<_Args>(__args)...), + _Bound_indexes()); + else + return _Bind_ref(__self) + .template __call_v<_Result>(std::forward_as_tuple + (std::forward<_Args>(__args)...), + _Bound_indexes()); + } +# endif +# pragma GCC diagnostic pop +#else // Call unqualified template<typename... _Args, typename _Result = _Res_type<tuple<_Args...>>> @@ -639,6 +724,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Bound_indexes()); } #endif // volatile +#endif }; /// Type of the function object returned from bind<R>(). @@ -919,116 +1005,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward<_BoundArgs>(__args)...); } -#ifdef __cpp_lib_bind_front // C++ >= 20 - - template<typename _Fd, typename... _BoundArgs> - struct _Bind_front +#if __cpp_lib_bind_front >= 202306L || __cpp_lib_bind_back >= 202306L + template <auto __fn> + struct _Bind_fn_t { - static_assert(is_move_constructible_v<_Fd>); - static_assert((is_move_constructible_v<_BoundArgs> && ...)); - - // First parameter is to ensure this constructor is never used - // instead of the copy/move constructor. - template<typename _Fn, typename... _Args> - explicit constexpr - _Bind_front(int, _Fn&& __fn, _Args&&... __args) - noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>, - is_nothrow_constructible<_BoundArgs, _Args>...>::value) - : _M_fd(std::forward<_Fn>(__fn)), - _M_bound_args(std::forward<_Args>(__args)...) - { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); } - -#if __cpp_explicit_this_parameter - template<typename _Self, typename... _CallArgs> - constexpr - invoke_result_t<__like_t<_Self, _Fd>, __like_t<_Self, _BoundArgs>..., _CallArgs...> - operator()(this _Self&& __self, _CallArgs&&... __call_args) - noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>, - __like_t<_Self, _BoundArgs>..., _CallArgs...>) - { - return _S_call(__like_t<_Self, _Bind_front>(__self), _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } -#else - template<typename... _CallArgs> - requires true - constexpr - invoke_result_t<_Fd&, _BoundArgs&..., _CallArgs...> - operator()(_CallArgs&&... __call_args) & - noexcept(is_nothrow_invocable_v<_Fd&, _BoundArgs&..., _CallArgs...>) - { - return _S_call(*this, _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } - - template<typename... _CallArgs> - requires true - constexpr - invoke_result_t<const _Fd&, const _BoundArgs&..., _CallArgs...> - operator()(_CallArgs&&... __call_args) const & - noexcept(is_nothrow_invocable_v<const _Fd&, const _BoundArgs&..., - _CallArgs...>) - { - return _S_call(*this, _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } - - template<typename... _CallArgs> - requires true - constexpr - invoke_result_t<_Fd, _BoundArgs..., _CallArgs...> - operator()(_CallArgs&&... __call_args) && - noexcept(is_nothrow_invocable_v<_Fd, _BoundArgs..., _CallArgs...>) - { - return _S_call(std::move(*this), _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } - - template<typename... _CallArgs> - requires true - constexpr - invoke_result_t<const _Fd, const _BoundArgs..., _CallArgs...> - operator()(_CallArgs&&... __call_args) const && - noexcept(is_nothrow_invocable_v<const _Fd, const _BoundArgs..., - _CallArgs...>) - { - return _S_call(std::move(*this), _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) & = delete; - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) const & = delete; - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) && = delete; - - template<typename... _CallArgs> - void operator()(_CallArgs&&...) const && = delete; -#endif - - private: - using _BoundIndices = index_sequence_for<_BoundArgs...>; - - template<typename _Tp, size_t... _Ind, typename... _CallArgs> - static constexpr - decltype(auto) - _S_call(_Tp&& __g, index_sequence<_Ind...>, _CallArgs&&... __call_args) - { - return std::invoke(std::forward<_Tp>(__g)._M_fd, - std::get<_Ind>(std::forward<_Tp>(__g)._M_bound_args)..., - std::forward<_CallArgs>(__call_args)...); - } - - [[no_unique_address]] _Fd _M_fd; - [[no_unique_address]] std::tuple<_BoundArgs...> _M_bound_args; + using _Fn = const decltype(__fn)&; + template <typename... _Args> + requires is_invocable_v<_Fn, _Args...> + constexpr static decltype(auto) + operator()(_Args&&... __args) + noexcept(is_nothrow_invocable_v<_Fn, _Args...>) + { return std::invoke(__fn, std::forward<_Args>(__args)...); } }; +#endif - template<typename _Fn, typename... _Args> - using _Bind_front_t = _Bind_front<decay_t<_Fn>, decay_t<_Args>...>; - +#ifdef __cpp_lib_bind_front // C++ >= 20 /** Create call wrapper by partial application of arguments to function. * * The result of `std::bind_front(f, args...)` is a function object that @@ -1047,57 +1038,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return _Bind_front_t<_Fn, _Args...>(0, std::forward<_Fn>(__fn), std::forward<_Args>(__args)...); } -#endif // __cpp_lib_bind_front -#ifdef __cpp_lib_bind_back // C++ >= 23 - template<typename _Fd, typename... _BoundArgs> - struct _Bind_back +#if __cpp_lib_bind_front >= 202306L + /** Create call wrapper by partial application of arguments to function. + * + * The result of `std::bind_front<fn>(bind_args...)` is a function object + * that stores the bound arguments, `bind_args...`. When that function + * object is invoked with `call_args...` it returns the result of calling + * `fn(bind_args..., call_args...)`. + * + * @since C++26 + */ + template<auto __fn, typename... _BindArgs> + constexpr decltype(auto) + bind_front(_BindArgs&&... __bind_args) + noexcept(__and_v<is_nothrow_constructible<_BindArgs>...>) { - static_assert(is_move_constructible_v<_Fd>); - static_assert((is_move_constructible_v<_BoundArgs> && ...)); - - // First parameter is to ensure this constructor is never used - // instead of the copy/move constructor. - template<typename _Fn, typename... _Args> - explicit constexpr - _Bind_back(int, _Fn&& __fn, _Args&&... __args) - noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>, - is_nothrow_constructible<_BoundArgs, _Args>...>::value) - : _M_fd(std::forward<_Fn>(__fn)), - _M_bound_args(std::forward<_Args>(__args)...) - { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); } - - template<typename _Self, typename... _CallArgs> - constexpr - invoke_result_t<__like_t<_Self, _Fd>, _CallArgs..., __like_t<_Self, _BoundArgs>...> - operator()(this _Self&& __self, _CallArgs&&... __call_args) - noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>, - _CallArgs..., __like_t<_Self, _BoundArgs>...>) - { - return _S_call(__like_t<_Self, _Bind_back>(__self), _BoundIndices(), - std::forward<_CallArgs>(__call_args)...); - } - - private: - using _BoundIndices = index_sequence_for<_BoundArgs...>; - - template<typename _Tp, size_t... _Ind, typename... _CallArgs> - static constexpr - decltype(auto) - _S_call(_Tp&& __g, index_sequence<_Ind...>, _CallArgs&&... __call_args) - { - return std::invoke(std::forward<_Tp>(__g)._M_fd, - std::forward<_CallArgs>(__call_args)..., - std::get<_Ind>(std::forward<_Tp>(__g)._M_bound_args)...); - } - - [[no_unique_address]] _Fd _M_fd; - [[no_unique_address]] std::tuple<_BoundArgs...> _M_bound_args; - }; + using _Fn = decltype(__fn); + if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>) + static_assert(__fn != nullptr); + + if constexpr (sizeof...(_BindArgs) == 0) + return _Bind_fn_t<__fn>{}; + else + return _Bind_front_t<_Bind_fn_t<__fn>, _BindArgs...>(0, + _Bind_fn_t<__fn>{}, std::forward<_BindArgs>(__bind_args)...); + } - template<typename _Fn, typename... _Args> - using _Bind_back_t = _Bind_back<decay_t<_Fn>, decay_t<_Args>...>; +#endif // __cpp_lib_bind_front // C++26 +#endif // __cpp_lib_bind_front +#ifdef __cpp_lib_bind_back // C++ >= 23 /** Create call wrapper by partial application of arguments to function. * * The result of `std::bind_back(f, args...)` is a function object that @@ -1116,6 +1087,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return _Bind_back_t<_Fn, _Args...>(0, std::forward<_Fn>(__fn), std::forward<_Args>(__args)...); } + +#if __cpp_lib_bind_back >= 202306L + + /** Create call wrapper by partial application of arguments to function. + * + * The result of `std::bind_back<fn>(bind_args...)` is a function object + * that stores the arguments, `bind_args...`. When that function object + * is invoked with `call_args...` it returns the result of calling + * `fn(call_args..., bind_args...)`. + * + * @since C++26 + */ + template<auto __fn, typename... _BindArgs> + constexpr decltype(auto) + bind_back(_BindArgs&&... __bind_args) + noexcept(__and_v<is_nothrow_constructible<_BindArgs>...>) + { + using _Fn = decltype(__fn); + if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>) + static_assert(__fn != nullptr); + + if constexpr (sizeof...(_BindArgs) == 0) + return _Bind_fn_t<__fn>{}; + else + return _Bind_back_t<_Bind_fn_t<__fn>, _BindArgs...>(0, + _Bind_fn_t<__fn>{}, std::forward<_BindArgs>(__bind_args)...); + } +#endif // __cpp_lib_bind_back // C++26, nttp #endif // __cpp_lib_bind_back #if __cplusplus >= 201402L @@ -1140,6 +1139,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Not_fn(_Not_fn&& __fn) = default; ~_Not_fn() = default; +#if _GLIBCXX_EXPLICIT_THIS_PARAMETER +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this + template<typename _Self, typename... _Args> + _GLIBCXX20_CONSTEXPR + decltype(_S_not<__inv_res_t<__like_t<_Self, _Fn>, _Args...>>()) + operator()(this _Self&& __self, _Args&&... __args) + noexcept(__is_nothrow_invocable<__like_t<_Self, _Fn>, _Args...>::value + && noexcept(_S_not<__inv_res_t<__like_t<_Self, _Fn>, _Args...>>())) + { + return !std::__invoke(__like_t<_Self, _Not_fn>(__self)._M_fn, + std::forward<_Args>(__args)...); + } +# pragma GCC diagnostic pop +#else // Macro to define operator() with given cv-qualifiers ref-qualifiers, // forwarding _M_fn and the function arguments with the same qualifiers, // and deducing the return type and exception-specification. @@ -1165,6 +1179,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NOT_FN_CALL_OP( && ) _GLIBCXX_NOT_FN_CALL_OP( const && ) #undef _GLIBCXX_NOT_FN_CALL_OP +#endif private: _Fn _M_fn; @@ -1216,7 +1231,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return _Not_fn<std::decay_t<_Fn>>{std::forward<_Fn>(__fn), 0}; } -#endif + +#if __cpp_lib_not_fn >= 202306L + /** Wrap a function type to create a function object that negates its result. + * + * The function template `std::not_fn` creates a "forwarding call wrapper", + * which is a function object that when called forwards its arguments to + * its invocable template argument. + * + * The result of invoking the wrapper is the negation (using `!`) of + * the wrapped function object. + * + * @ingroup functors + * @since C++26 + */ + template<auto __fn> + constexpr decltype(auto) + not_fn() noexcept + { + using _Fn = decltype(__fn); + if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>) + static_assert(__fn != nullptr); + return []<typename... _Args>(_Args&&... __args) static + noexcept(noexcept( + !std::invoke(__fn, std::forward<_Args>(__args)...) )) + -> decltype(auto) + requires requires { + !std::invoke(__fn, std::forward<_Args>(__args)...); } + { return !std::invoke(__fn, std::forward<_Args>(__args)...); }; + }; +#endif // __cpp_lib_not_fn >= 202306L +#endif // __cpp_lib_not_fn #if __cplusplus >= 201703L // Searchers @@ -1410,6 +1455,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator()(_RandomAccessIterator2 __first, _RandomAccessIterator2 __last) const { +#ifdef __glibcxx_concepts // >= C++20 + // Value types must be the same for hash function and predicate + // to give consistent results for lookup in the map. + static_assert(is_same_v<iter_value_t<_RAIter>, + iter_value_t<_RandomAccessIterator2>>); +#endif const auto& __pred = this->_M_pred(); auto __patlen = _M_pat_end - _M_pat; if (__patlen == 0) @@ -1471,6 +1522,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator()(_RandomAccessIterator2 __first, _RandomAccessIterator2 __last) const { +#ifdef __glibcxx_concepts // >= C++20 + // Value types must be the same for hash function and predicate + // to give consistent results for lookup in the map. + static_assert(is_same_v<iter_value_t<_RAIter>, + iter_value_t<_RandomAccessIterator2>>); +#endif auto __patlen = _M_pat_end - _M_pat; if (__patlen == 0) return std::make_pair(__first, __first); @@ -1487,7 +1544,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } if (__j < 0) { - const auto __match = __first + __i + 1; + const auto __match = __first + __diff_type(__i + 1); return std::make_pair(__match, __match + __patlen); } __i += std::max(_M_bad_char_shift(__first[__i]), diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index b7ab233..0806900 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -1486,12 +1486,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)> final : __future_base::_Task_state_base<_Res(_Args...)> { +#ifdef __cpp_lib_is_invocable // C++ >= 17 + static_assert(is_invocable_r_v<_Res, _Fn&, _Args...>); +#else + static_assert(__is_invocable<_Fn&, _Args...>::value, + "_Fn& is invocable with _Args..."); +#endif + template<typename _Fn2> _Task_state(_Fn2&& __fn, const _Alloc& __a) : _Task_state_base<_Res(_Args...)>(__a), _M_impl(std::forward<_Fn2>(__fn), __a) { } + template<typename _Fn2> + static shared_ptr<_Task_state_base<_Res(_Args...)>> + _S_create(_Fn2&& __fn, const _Alloc& __a) + { + return std::allocate_shared<_Task_state>(__a, + std::forward<_Fn2>(__fn), + __a); + } + private: virtual void _M_run(_Args&&... __args) @@ -1515,7 +1531,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } virtual shared_ptr<_Task_state_base<_Res(_Args...)>> - _M_reset(); + _M_reset() + { return _S_create(std::move(_M_impl._M_fn), _M_impl); } struct _Impl : _Alloc { @@ -1525,38 +1542,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Fn _M_fn; } _M_impl; }; - - template<typename _Signature, typename _Fn, - typename _Alloc = std::allocator<int>> - shared_ptr<__future_base::_Task_state_base<_Signature>> - __create_task_state(_Fn&& __fn, const _Alloc& __a = _Alloc()) - { - typedef typename decay<_Fn>::type _Fn2; - typedef __future_base::_Task_state<_Fn2, _Alloc, _Signature> _State; - return std::allocate_shared<_State>(__a, std::forward<_Fn>(__fn), __a); - } - - template<typename _Fn, typename _Alloc, typename _Res, typename... _Args> - shared_ptr<__future_base::_Task_state_base<_Res(_Args...)>> - __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)>::_M_reset() - { - return __create_task_state<_Res(_Args...)>(std::move(_M_impl._M_fn), - static_cast<_Alloc&>(_M_impl)); - } /// @endcond /// packaged_task template<typename _Res, typename... _ArgTypes> class packaged_task<_Res(_ArgTypes...)> { - typedef __future_base::_Task_state_base<_Res(_ArgTypes...)> _State_type; + using _State_type = __future_base::_Task_state_base<_Res(_ArgTypes...)>; shared_ptr<_State_type> _M_state; // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3039. Unnecessary decay in thread and packaged_task template<typename _Fn, typename _Fn2 = __remove_cvref_t<_Fn>> - using __not_same - = typename enable_if<!is_same<packaged_task, _Fn2>::value>::type; + using __not_same = __enable_if_t<!is_same<packaged_task, _Fn2>::value>; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4154. The Mandates for std::packaged_task's constructor + // from a callable entity should consider decaying. + template<typename _Fn, typename _Alloc = std::allocator<int>> + using _Task_state + = __future_base::_Task_state<__decay_t<_Fn>, _Alloc, + _Res(_ArgTypes...)>; public: // Construction and destruction @@ -1565,16 +1571,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Fn, typename = __not_same<_Fn>> explicit packaged_task(_Fn&& __fn) - : _M_state( - __create_task_state<_Res(_ArgTypes...)>(std::forward<_Fn>(__fn))) - { -#ifdef __cpp_lib_is_invocable // C++ >= 17 - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 4154. The Mandates for std::packaged_task's constructor - // from a callable entity should consider decaying - static_assert(is_invocable_r_v<_Res, decay_t<_Fn>&, _ArgTypes...>); -#endif - } + : _M_state(_Task_state<_Fn>::_S_create(std::forward<_Fn>(__fn), {})) + { } #if __cplusplus < 201703L // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -1583,8 +1581,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 2921. packaged_task and type-erased allocators template<typename _Fn, typename _Alloc, typename = __not_same<_Fn>> packaged_task(allocator_arg_t, const _Alloc& __a, _Fn&& __fn) - : _M_state(__create_task_state<_Res(_ArgTypes...)>( - std::forward<_Fn>(__fn), __a)) + : _M_state(_Task_state<_Fn, _Alloc>::_S_create(std::forward<_Fn>(__fn), + __a)) { } // _GLIBCXX_RESOLVE_LIB_DEFECTS diff --git a/libstdc++-v3/include/std/generator b/libstdc++-v3/include/std/generator index 3f781f1..7ab2c9e 100644 --- a/libstdc++-v3/include/std/generator +++ b/libstdc++-v3/include/std/generator @@ -153,6 +153,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept { return _Recursive_awaiter { std::move(__r.range) }; } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3899. co_yielding elements of an lvalue generator is + // unnecessarily inefficient + template<typename _R2, typename _V2, typename _A2, typename _U2> + requires std::same_as<_Yield2_t<_R2, _V2>, _Yielded> + auto + yield_value(ranges::elements_of<generator<_R2, _V2, _A2>&, _U2> __r) + noexcept + { return _Recursive_awaiter { std::move(__r.range) }; } + template<ranges::input_range _R, typename _Alloc> requires convertible_to<ranges::range_reference_t<_R>, _Yielded> auto diff --git a/libstdc++-v3/include/std/inplace_vector b/libstdc++-v3/include/std/inplace_vector new file mode 100644 index 0000000..0f7716c --- /dev/null +++ b/libstdc++-v3/include/std/inplace_vector @@ -0,0 +1,1369 @@ +// Sequence container with fixed capacity -*- C++ -*- + +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file include/inplace_vector + * This is a Standard C++ Library header. + * @ingroup sequences + */ + +#ifndef _GLIBCXX_INPLACE_VECTOR +#define _GLIBCXX_INPLACE_VECTOR 1 + +#pragma GCC system_header + +#define __glibcxx_want_inplace_vector +#include <bits/version.h> + +#ifdef __glibcxx_inplace_vector // C++ >= 26 +#include <compare> +#include <initializer_list> +#include <bits/range_access.h> +#include <bits/ranges_base.h> // borrowed_iterator_t, __detail::__container_compatible_range +#include <bits/ranges_util.h> // subrange +#include <bits/ranges_uninitialized.h> +#include <bits/stl_construct.h> +#include <bits/stl_uninitialized.h> +#include <bits/stl_algo.h> // rotate + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION +_GLIBCXX_BEGIN_NAMESPACE_CONTAINER + + // [indirect], class template indirect + template<typename _Tp, size_t _Nm> + class inplace_vector + { + public: + + // types: + using value_type = _Tp; + using pointer = _Tp*; + using const_pointer = const _Tp*; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator + = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>; + using const_iterator + = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + // [containers.sequences.inplace.vector.cons], construct/copy/destroy + constexpr + inplace_vector() noexcept + { _M_init(); } + + constexpr explicit + inplace_vector(size_type __n) + { + _M_init(); + _S_reserve(__n); + std::uninitialized_value_construct_n(data(), __n); + _M_size = __n; + } + + constexpr + inplace_vector(size_type __n, const _Tp& __value) + { + _M_init(); + _S_reserve(__n); + std::uninitialized_fill_n(data(), __n, __value); + _M_size = __n; + } + + template<__any_input_iterator _InputIterator> + constexpr + inplace_vector(_InputIterator __first, _InputIterator __last) + : inplace_vector() + { + if (const auto __n = _S_distance(__first, __last)) + { + _S_reserve(__n); + std::uninitialized_copy(__first, __last, data()); + _M_size = __n; + } + else + { + while (__first != __last) + emplace_back(*__first++); + } + } + + template <__detail::__container_compatible_range<_Tp> _Rg> + constexpr + inplace_vector(from_range_t, _Rg&& __rg) + : inplace_vector() + { append_range(__rg); } + + constexpr + inplace_vector(initializer_list<_Tp> __il) + { + _M_init(); + _S_reserve(__il.size()); + std::uninitialized_copy(__il.begin(), __il.end(), data()); + _M_size = __il.size(); + } + + inplace_vector(const inplace_vector&) + requires is_trivially_copy_constructible_v<_Tp> + = default; + + constexpr + inplace_vector(const inplace_vector& __other) + noexcept(is_nothrow_copy_constructible_v<_Tp>) + { + _M_init(); + std::uninitialized_copy(__other.begin(), __other.end(), data()); + _M_size = __other.size(); + } + + inplace_vector(inplace_vector&&) + requires is_trivially_move_constructible_v<_Tp> + = default; + + constexpr + inplace_vector(inplace_vector&& __other) + noexcept(is_nothrow_move_constructible_v<_Tp>) + { + _M_init(); + std::uninitialized_move(__other.begin(), __other.end(), data()); + _M_size = __other.size(); + } + + ~inplace_vector() + requires is_trivially_destructible_v<_Tp> + = default; + + constexpr + ~inplace_vector() + { clear(); } + + inplace_vector& + operator=(const inplace_vector&) + requires is_trivially_copy_assignable_v<_Tp> + && is_trivially_copy_constructible_v<_Tp> + && is_trivially_destructible_v<_Tp> + = default; + + constexpr inplace_vector& + operator=(const inplace_vector& __other) + noexcept(is_nothrow_copy_assignable_v<_Tp> + && is_nothrow_copy_constructible_v<_Tp>) + { + if (std::addressof(__other) != this) [[likely]] + assign(__other.begin(), __other.end()); + return *this; + } + + inplace_vector& + operator=(inplace_vector&&) + requires is_trivially_move_assignable_v<_Tp> + && is_trivially_move_constructible_v<_Tp> + && is_trivially_destructible_v<_Tp> + = default; + + constexpr inplace_vector& + operator=(inplace_vector&& __other) + noexcept(is_nothrow_move_assignable_v<_Tp> + && is_nothrow_move_constructible_v<_Tp>) + { + if (std::addressof(__other) != this) [[likely]] + assign(std::make_move_iterator(__other.begin()), + std::make_move_iterator(__other.end())); + return *this; + } + + constexpr inplace_vector& + operator=(initializer_list<_Tp> __il) + { + assign(__il.begin(), __il.end()); + return *this; + } + + template<__any_input_iterator _InputIterator> + constexpr void + assign(_InputIterator __first, _InputIterator __last) + { + if (const auto __n = _S_distance(__first, __last)) + { + _S_reserve(__n); + if (_M_size <= __n) + { + for (size_t __i = 0; __i < _M_size; ++__i, (void)++__first) + _M_elems[__i] = *__first; + std::uninitialized_copy(__first, __last, end()); + } + else + std::destroy(std::copy(__first, __last, begin()), end()); + _M_size = __n; + } + else + { + size_t __i = 0; + for (;__first != __last && __i < _M_size; ++__first) + _M_elems[__i++] = *__first; + if (__first == __last) + { + std::_Destroy_n(data() + __i, _M_size - __i); + _M_size = __i; + } + else + { + while (__first != __last) + emplace_back(*__first++); + } + } + } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr void + assign_range(_Rg&& __rg) + { + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) + { + const auto __sz = ranges::distance(__rg); + if (__sz > _Nm) + __throw_bad_alloc(); + if (__sz <= size()) + { + ranges::copy_n(ranges::begin(__rg), __sz, data()); + std::destroy(data() + __sz, data() + _M_size); + } + else + { + auto [__in, __out] = ranges::copy_n( + ranges::begin(__rg), _M_size, + data()); + ranges::uninitialized_copy( + std::move(__in), ranges::end(__rg), + __out, unreachable_sentinel); + } + _M_size = __sz; + } + else + { + auto __in = ranges::begin(__rg); + auto __end = ranges::end(__rg); + size_type __n = 0; + for (; __n < _M_size && __in != __end; ++__in) + _M_elems[__n++] = *__in; + + if (__in == __end) + { + std::destroy(data() + __n, data() + _M_size); + _M_size = __n; + return; + } + else if (__n < _Nm) + { + auto __res = ranges::uninitialized_copy( + std::move(__in), __end, + data() + __n, data() + _Nm); + _M_size = __res.out - data(); + if (__res.in == ranges::end(__rg)) + return; + } + __throw_bad_alloc(); + } + } + + constexpr void + assign(size_type __n, const _Tp& __u) + { + _S_reserve(__n); + if (_M_size <= __n) + std::uninitialized_fill_n(std::fill_n(data(), _M_size, __u), + __n - _M_size, __u); + else + std::destroy_n(std::fill_n(data(), __n, __u), _M_size - __n); + _M_size = __n; + } + + constexpr void + assign(initializer_list<_Tp> __il) + { assign(__il.begin(), __il.end()); } + + // iterators + [[nodiscard]] + constexpr iterator + begin() noexcept { return iterator(data()); } + + [[nodiscard]] + constexpr const_iterator + begin() const noexcept { return const_iterator(data()); } + + [[nodiscard]] + constexpr iterator + end() noexcept + { return iterator(data() + _M_size); } + + [[nodiscard]] + constexpr const_iterator + end() const noexcept + { return const_iterator(data() + _M_size); } + + [[nodiscard]] + constexpr reverse_iterator + rbegin() noexcept + { return reverse_iterator(end()); } + + [[nodiscard]] + constexpr const_reverse_iterator + rbegin() const noexcept + { return const_reverse_iterator(end()); } + + [[nodiscard]] + constexpr reverse_iterator + rend() noexcept { return reverse_iterator(begin()); } + + [[nodiscard]] + constexpr const_reverse_iterator + rend() const noexcept { return const_reverse_iterator(begin()); } + + [[nodiscard]] + constexpr const_iterator + cbegin() const noexcept { return begin(); } + + [[nodiscard]] + constexpr const_iterator + cend() const noexcept { return end(); } + + [[nodiscard]] + constexpr const_reverse_iterator + crbegin() const noexcept { return rbegin(); } + + [[nodiscard]] + constexpr const_reverse_iterator + crend() const noexcept { return rend(); } + + // [containers.sequences.inplace.vector.members] size/capacity + [[nodiscard]] + constexpr bool + empty() const noexcept { return _M_size == 0; } + + [[nodiscard]] + constexpr size_type + size() const noexcept + { + if (_M_size > _Nm) + __builtin_unreachable(); + return _M_size; + } + + [[nodiscard]] + static constexpr size_type + max_size() noexcept { return _Nm; } + + [[nodiscard]] + static constexpr size_type + capacity() noexcept { return _Nm; } + + constexpr void + resize(size_type __n) + { + _S_reserve(__n); + if (__n > _M_size) + std::uninitialized_value_construct_n(data() + _M_size, __n - _M_size); + else if (__n < _M_size) + std::destroy_n(data() + __n, _M_size - __n); + _M_size = __n; + } + + constexpr void + resize(size_type __n, const _Tp& __c) + { + _S_reserve(__n); + if (__n > _M_size) + std::uninitialized_fill_n(data() + _M_size, __n - _M_size, __c); + else if (__n < _M_size) + std::destroy_n(data() + __n, _M_size - __n); + _M_size = __n; + } + + static constexpr void + reserve(size_type __n) + { _S_reserve(__n); } + + static constexpr void + shrink_to_fit() { } + + // element access + [[nodiscard]] + constexpr reference + operator[](size_type __n) + { + __glibcxx_requires_subscript(__n); + return _M_elems[__n]; + } + + [[nodiscard]] + constexpr const_reference + operator[](size_type __n) const + { + __glibcxx_requires_subscript(__n); + return _M_elems[__n]; + } + + [[nodiscard]] + constexpr const_reference + at(size_type __n) const + { + if (__n >= _M_size) + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n " + "(which is %zu) " + ">= size() (which is %zu)"), + __n, _M_size); + return _M_elems[__n]; + } + + [[nodiscard]] + constexpr reference + at(size_type __n) + { + if (__n >= _M_size) + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n " + "(which is %zu) " + ">= size() (which is %zu)"), + __n, _M_size); + return _M_elems[__n]; + } + + [[nodiscard]] + constexpr reference + front() + { + __glibcxx_requires_nonempty(); + return _M_elems[0]; + } + + [[nodiscard]] + constexpr const_reference + front() const + { + __glibcxx_requires_nonempty(); + return _M_elems[0]; + } + + [[nodiscard]] + constexpr reference + back() + { + __glibcxx_requires_nonempty(); + return _M_elems[_M_size - 1]; + } + + [[nodiscard]] + constexpr const_reference + back() const + { + __glibcxx_requires_nonempty(); + return _M_elems[_M_size - 1]; + } + + // [containers.sequences.inplace.vector.data], data access + + [[nodiscard]] + constexpr _Tp* + data() noexcept + { return static_cast<pointer>(_M_elems); } + + [[nodiscard]] + constexpr const _Tp* + data() const noexcept + { return static_cast<const_pointer>(_M_elems); } + + // [containers.sequences.inplace.vector.modifiers], modifiers + template<typename... _Args> + constexpr _Tp& + emplace_back(_Args&&... __args) + { + if (_M_size >= _Nm) + __throw_bad_alloc(); + return unchecked_emplace_back(std::forward<_Args>(__args)...); + } + + constexpr _Tp& + push_back(const _Tp& __x) + { return emplace_back(__x); } + + constexpr _Tp& + push_back(_Tp&& __x) + { return emplace_back(std::move(__x)); } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr void + append_range(_Rg&& __rg) + { + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) + { + const auto __sz = ranges::distance(__rg); + if (__sz > (_Nm - size())) + __throw_bad_alloc(); + // Bounded on output range due PR121143 + ranges::uninitialized_copy( + ranges::begin(__rg), unreachable_sentinel, + data() + _M_size, data() + _M_size + __sz); + _M_size += size_type(__sz); + } + else + { + ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm); + auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail); + _M_size = __out - data(); + if (__in != ranges::end(__rg)) + __throw_bad_alloc(); + } + } + + constexpr void + pop_back() + { + __glibcxx_requires_nonempty(); + --_M_size; + _M_elems[_M_size].~_Tp(); + } + + template<typename... _Args> + constexpr _Tp* + try_emplace_back(_Args&&... __args) + { + if (_M_size >= _Nm) [[unlikely]] + return nullptr; + auto& __r = unchecked_emplace_back(std::forward<_Args>(__args)...); + return __builtin_addressof(__r); + } + + constexpr _Tp* + try_push_back(const _Tp& __x) + { + if (_M_size >= _Nm) [[unlikely]] + return nullptr; + return __builtin_addressof(unchecked_emplace_back(__x)); + } + + constexpr _Tp* + try_push_back(_Tp&& __x) + { + if (_M_size >= _Nm) [[unlikely]] + return nullptr; + return __builtin_addressof(unchecked_emplace_back(std::move(__x))); + } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr ranges::borrowed_iterator_t<_Rg> + try_append_range(_Rg&& __rg) + { + if constexpr (ranges::sized_range<_Rg>) + { + auto __n = ranges::distance(__rg); + if (__n == 0) [[unlikely]] + return ranges::begin(__rg); + + const auto __end = data() + _M_size; + const size_t __avail = _Nm - size(); + if (__n <= __avail) + _M_size += size_type(__n); + else + { + __n = __avail; + _M_size = _Nm; + } + return ranges::uninitialized_copy_n( + ranges::begin(__rg), __n, + __end, unreachable_sentinel).in; + } + else + { + ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm); + auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail); + _M_size = __out - data(); + return std::move(__in); + } + } + + template<typename... _Args> + constexpr _Tp& + unchecked_emplace_back(_Args&&... __args) + { + __glibcxx_assert(_M_size < _Nm); + auto __p = std::construct_at(data() + _M_size, + std::forward<_Args>(__args)...); + ++_M_size; + return *__p; + } + + constexpr _Tp& + unchecked_push_back(const _Tp& __x) + { return unchecked_emplace_back(__x); } + + constexpr _Tp& + unchecked_push_back(_Tp&& __x) + { return unchecked_emplace_back(std::move(__x)); } + + template<typename... _Args> + constexpr iterator + emplace(const_iterator __position, _Args&&... __args) + { + size_t __b = __position - cbegin(); // elements before position + __glibcxx_assert(__b <= _M_size); + if (_M_size >= _Nm) + __throw_bad_alloc(); + iterator __pos = begin() + __b; + std::construct_at(data() + _M_size, std::forward<_Args>(__args)...); + if (_M_size++) + std::rotate(__pos, end() - 1, end()); + return __pos; + } + + constexpr iterator + insert(const_iterator __position, const _Tp& __x) + { return emplace(__position, __x); } + + constexpr iterator + insert(const_iterator __position, _Tp&& __x) + { return emplace(__position, std::move(__x)); } + + constexpr iterator + insert(const_iterator __position, size_type __n, const _Tp& __x) + { + size_t __b = __position - cbegin(); // elements before position + __glibcxx_assert(__b <= _M_size); + if ((_Nm - _M_size) < __n) + __throw_bad_alloc(); + iterator __pos = begin() + __b; + std::uninitialized_fill_n(data() + _M_size, __n, __x); + if (std::__exchange(_M_size, _M_size + __n)) + std::rotate(__pos, end() - __n, end()); + return __pos; + } + + template<__any_input_iterator _InputIterator> + constexpr iterator + insert(const_iterator __position, _InputIterator __first, + _InputIterator __last) + { + size_t __b = __position - cbegin(); // elements before position + __glibcxx_assert(__b <= _M_size); + iterator __pos = begin() + __b; + const size_t __s = _M_size; + if (const auto __n = _S_distance(__first, __last)) + { + if ((_Nm - _M_size) < __n) + __throw_bad_alloc(); + std::uninitialized_copy(__first, __last, data() + _M_size); + _M_size += __n; + } + else + { + while (__first != __last) + emplace_back(*__first++); + } + if (__s) + std::rotate(__pos, begin() + __s, end()); + return __pos; + } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr iterator + insert_range(const_iterator __position, _Rg&& __rg) + { + iterator __pos = begin() + (__position - cbegin()); + const auto __end = end(); + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) + { + const auto __len = ranges::distance(__rg); + if (__len > (_Nm - size())) + __throw_bad_alloc(); + if (!__len) [[unlikely]] + return __pos; + + const size_type __n = size_type(__len); + const size_type __num_after = __end - __pos; + if (__num_after >= __n) + { + ranges::uninitialized_move(__end - __n, __end, + __end, unreachable_sentinel); + _M_size += __n; + ranges::move_backward(__pos, __end - __n, __end); + ranges::copy(__rg, __pos); + } + else if constexpr (ranges::forward_range<_Rg>) + { + auto __mid = ranges::next(ranges::begin(__rg), __num_after); + ranges::uninitialized_copy(__mid, ranges::end(__rg), + __end, unreachable_sentinel); + _M_size += __n - __num_after; + ranges::uninitialized_move(__pos, __end, + __pos + __n, unreachable_sentinel); + _M_size += __num_after; + ranges::copy(ranges::begin(__rg), __mid, __pos); + } + else + { + ranges::uninitialized_copy( + ranges::begin(__rg), ranges::end(__rg), + __end, unreachable_sentinel); + _M_size += __n; + std::rotate(__pos, __end, end()); + } + } + else + { + append_range(__rg); + std::rotate(__pos, __end, end()); + } + return __pos; + } + + constexpr iterator + insert(const_iterator __position, initializer_list<_Tp> __il) + { return insert(__position, __il.begin(), __il.end()); } + + constexpr iterator + erase(const_iterator __position) + { + size_t __n = __position - cbegin(); + __glibcxx_assert(__n < _M_size); + iterator __pos = begin() + __n; + std::move(__pos + 1, end(), __pos); + pop_back(); + return __pos; + } + + constexpr iterator + erase(const_iterator __first, const_iterator __last) + { + size_t __n = __first - cbegin(); + size_t __x = __last - __first; + __glibcxx_assert(__n <= _M_size); + __glibcxx_assert(__x <= _M_size); + iterator __pos = begin() + __n; + iterator __end = std::move(__pos + __x, end(), __pos); + std::destroy_n(__end, __x); + _M_size -= __x; + return __pos; + } + + constexpr void + swap(inplace_vector& __x) + noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>) + { + inplace_vector* __vs[2]{ this, std::addressof(__x) }; + const auto __smaller = __vs[__x.size() < size()]; + const auto __bigger = __vs[__x.size() >= size()]; + size_type __n = __smaller->size(); + size_type __n2 = __bigger->size(); + + if constexpr (is_nothrow_move_constructible_v<_Tp>) + { + for (size_type __i = __n; __i < __n2; ++__i) + { + std::construct_at(__smaller->data() + __i, + std::move(*(__bigger->data() + __i))); + std::destroy_at(__bigger->data() + __i); + } + } + else + { + std::uninitialized_copy(__bigger->data() + __n, + __bigger->data() + __n2, + __smaller->data() + __n); + std::destroy(__bigger->data() + __n, __bigger->data() + __n2); + } + __smaller->_M_size = __n2; + __bigger->_M_size = __n; + + using std::swap; + for (size_type __i = 0; __i < __n; __i++) + swap(_M_elems[__i], __x._M_elems[__i]); + } + + constexpr void + clear() noexcept + { + std::destroy_n(data(), size_t(_M_size)); + _M_size = 0; + } + + constexpr friend bool + operator==(const inplace_vector& __x, const inplace_vector& __y) + { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); } + + constexpr friend auto + operator<=>(const inplace_vector& __x, const inplace_vector& __y) + requires requires (const _Tp __t) { + { __t < __t } -> __detail::__boolean_testable; + } + { + return std::lexicographical_compare_three_way(__x.begin(), __x.end(), + __y.begin(), __y.end(), + __detail::__synth3way); + } + + // [inplace.vector.special], specialized algorithms + constexpr friend void + swap(inplace_vector& __x, inplace_vector& __y) + noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>) + { __x.swap(__y); } + + private: + union { + _Tp _M_elems[_Nm]; + }; + + // Check whether integer type _UInt is wide enough to store _Nm, + // so that we use a smaller type for _M_size when that saves space. + template<typename _UInt, bool = (alignof(_Tp) <= sizeof(_UInt))> + static constexpr bool __fits + = _Nm <= __gnu_cxx::__int_traits<_UInt>::__max; + + // Don't bother using a smaller type if alignment of the array elements + // means that it doesn't actually save space. + template<typename _UInt> + static constexpr bool __fits<_UInt, false> = false; + + static consteval auto __select_size_type() + { + if constexpr (__fits<unsigned char>) + return (unsigned char)0; +#if __SHRT_WIDTH__ < __SIZE_WIDTH__ + else if constexpr (__fits<unsigned short>) + return (unsigned short)0; +#endif +#if __INT_WIDTH__ < __SIZE_WIDTH__ && __INT_WIDTH__ > __SHRT_WIDTH__ + else if constexpr (__fits<unsigned int>) + return 0u; +#endif +#if __LONG_WIDTH__ < __SIZE_WIDTH__ && __LONG_WIDTH__ > __INT_WIDTH__ + else if constexpr (__fits<unsigned long>) + return 0ul; +#endif + else // Just use size_t. + return 0uz; + } + decltype(__select_size_type()) _M_size = 0; + + constexpr void + _M_init() + { + if !consteval + { +#if __glibcxx_start_lifetime_as + std::start_lifetime_as_array<_Tp>(data(), _Nm); +#endif + } + else + { + // TODO: use new(_M_elems) _Tp[_Nm]() once PR121068 is fixed + if constexpr (is_trivial_v<_Tp>) + for (size_t __i = 0; __i < _Nm; ++__i) + _M_elems[__i] = _Tp(); + else + __builtin_unreachable(); // only trivial types are supported at compile time + } + } + + static constexpr void + _S_reserve(size_t __n) + { + if (__n > _Nm) + __throw_bad_alloc(); + } + + template<typename _InputIterator> + constexpr static auto + _S_distance(_InputIterator __first, _InputIterator __last) + { + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator> + || forward_iterator<_InputIterator>) + return (size_type)ranges::distance(__first, __last); + else if constexpr (derived_from<__iter_category_t<_InputIterator>, + forward_iterator_tag>) + return (size_type)std::distance(__first, __last); + else + return false_type{}; + } + }; + + // specialization for zero capacity, that is required to be trivally copyable + // and empty regardless of _Tp. + template<typename _Tp> + class inplace_vector<_Tp, 0> + { + public: + // types: + using value_type = _Tp; + using pointer = _Tp*; + using const_pointer = const _Tp*; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator + = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>; + using const_iterator + = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + // [containers.sequences.inplace.vector.cons], construct/copy/destroy + inplace_vector() = default; + + constexpr explicit + inplace_vector(size_type __n) + { + if (__n != 0) + __throw_bad_alloc(); + } + + constexpr + inplace_vector(size_type __n, const _Tp& __value) + { + if (__n != 0) + __throw_bad_alloc(); + } + + template<__any_input_iterator _InputIterator> + constexpr + inplace_vector(_InputIterator __first, _InputIterator __last) + { + if (__first != __last) + __throw_bad_alloc(); + } + + template <__detail::__container_compatible_range<_Tp> _Rg> + constexpr + inplace_vector(from_range_t, _Rg&& __rg) + { + if (ranges::begin(__rg) != ranges::end(__rg)) + __throw_bad_alloc(); + } + + constexpr + inplace_vector(initializer_list<_Tp> __il) + { + if (__il.size() != 0) + __throw_bad_alloc(); + } + + inplace_vector(const inplace_vector&) = default; + inplace_vector(inplace_vector&&) = default; + + constexpr + ~inplace_vector() = default; + + inplace_vector& + operator=(const inplace_vector&) = default; + + inplace_vector& + operator=(inplace_vector&&) = default; + + constexpr inplace_vector& + operator=(initializer_list<_Tp> __il) + { + if (__il.size() != 0) + __throw_bad_alloc(); + return *this; + } + + template<__any_input_iterator _InputIterator> + constexpr void + assign(_InputIterator __first, _InputIterator __last) + { + if (__first != __last) + __throw_bad_alloc(); + } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr void + assign_range(_Rg&& __rg) + { + if (ranges::begin(__rg) != ranges::end(__rg)) + __throw_bad_alloc(); + } + + constexpr void + assign(size_type __n, const _Tp& __u) + { + if (__n != 0) + __throw_bad_alloc(); + } + + constexpr void + assign(initializer_list<_Tp> __il) + { + if (__il.size() != 0) + __throw_bad_alloc(); + } + + // iterators + [[nodiscard]] + constexpr iterator + begin() noexcept { return iterator(nullptr); } + + [[nodiscard]] + constexpr const_iterator + begin() const noexcept { return const_iterator(nullptr); } + + [[nodiscard]] + constexpr iterator + end() noexcept { return iterator(nullptr); } + + [[nodiscard]] + constexpr const_iterator + end() const noexcept { return const_iterator(nullptr); } + + [[nodiscard]] + constexpr reverse_iterator + rbegin() noexcept + { return reverse_iterator(end()); } + + [[nodiscard]] + constexpr const_reverse_iterator + rbegin() const noexcept + { return const_reverse_iterator(end()); } + + [[nodiscard]] + constexpr reverse_iterator + rend() noexcept { return reverse_iterator(begin()); } + + [[nodiscard]] + constexpr const_reverse_iterator + rend() const noexcept { return const_reverse_iterator(begin()); } + + [[nodiscard]] + constexpr const_iterator + cbegin() const noexcept { return begin(); } + + [[nodiscard]] + constexpr const_iterator + cend() const noexcept { return end(); } + + [[nodiscard]] + constexpr const_reverse_iterator + crbegin() const noexcept { return rbegin(); } + + [[nodiscard]] + constexpr const_reverse_iterator + crend() const noexcept { return rend(); } + + // [containers.sequences.inplace.vector.members] size/capacity + [[nodiscard]] + constexpr bool + empty() const noexcept { return true; } + + [[nodiscard]] + constexpr size_type + size() const noexcept { return 0; } + + [[nodiscard]] + static constexpr size_type + max_size() noexcept { return 0; } + + [[nodiscard]] + static constexpr size_type + capacity() noexcept { return 0; } + + constexpr void + resize(size_type __n) + { + if (__n != 0) + __throw_bad_alloc(); + } + + constexpr void + resize(size_type __n, const _Tp&) + { + if (__n != 0) + __throw_bad_alloc(); + } + + static constexpr void + reserve(size_type __n) + { + if (__n != 0) + __throw_bad_alloc(); + } + + static constexpr void + shrink_to_fit() { } + + // element access + [[nodiscard,noreturn]] + constexpr reference + operator[](size_type) + { __builtin_trap(); } + + [[nodiscard,noreturn]] + constexpr const_reference + operator[](size_type) const + { __builtin_trap(); } + + [[nodiscard,noreturn]] + constexpr const_reference + at(size_type __n) const + { + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n " + "(which is %zu) " + ">= size() (which is 0)"), + __n); + } + + [[nodiscard,noreturn]] + constexpr reference + at(size_type __n) + { + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n " + "(which is %zu) " + ">= size() (which is 0)"), + __n); + } + + [[nodiscard,noreturn]] + constexpr reference + front() + { __builtin_trap(); } + + [[nodiscard,noreturn]] + constexpr const_reference + front() const + { __builtin_trap(); } + + [[nodiscard,noreturn]] + constexpr reference + back() + { __builtin_trap(); } + + [[nodiscard,noreturn]] + constexpr const_reference + back() const + { __builtin_trap(); } + + // [containers.sequences.inplace.vector.data], data access + + [[nodiscard]] + constexpr _Tp* + data() noexcept + { return nullptr; } + + [[nodiscard]] + constexpr const _Tp* + data() const noexcept + { return nullptr; } + + // [containers.sequences.inplace.vector.modifiers], modifiers + template<typename... _Args> + [[noreturn]] + constexpr _Tp& + emplace_back(_Args&&...) + { __throw_bad_alloc(); } + + [[noreturn]] + constexpr _Tp& + push_back(const _Tp&) + { __throw_bad_alloc(); } + + [[noreturn]] + constexpr _Tp& + push_back(_Tp&&) + { __throw_bad_alloc(); } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr void + append_range(_Rg&& __rg) + { + if (ranges::begin(__rg) != ranges::end(__rg)) + __throw_bad_alloc(); + } + + [[noreturn]] + constexpr void + pop_back() + { __builtin_trap(); } + + template<typename... _Args> + constexpr _Tp* + try_emplace_back(_Args&&...) + { return nullptr; } + + constexpr _Tp* + try_push_back(const _Tp&) + { return nullptr; } + + constexpr _Tp* + try_push_back(_Tp&&) + { return nullptr; } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr ranges::borrowed_iterator_t<_Rg> + try_append_range(_Rg&& __rg) + { return ranges::begin(__rg); } + + template<typename... _Args> + [[noreturn]] + constexpr _Tp& + unchecked_emplace_back(_Args&&...) + { __builtin_trap(); } + + [[noreturn]] + constexpr _Tp& + unchecked_push_back(const _Tp&) + { __builtin_trap(); } + + [[noreturn]] + constexpr _Tp& + unchecked_push_back(_Tp&&) + { __builtin_trap(); } + + template<typename... _Args> + [[noreturn]] + constexpr iterator + emplace(const_iterator, _Args&&...) + { __throw_bad_alloc(); } + + [[noreturn]] + constexpr iterator + insert(const_iterator, const _Tp&) + { __throw_bad_alloc(); } + + [[noreturn]] + constexpr iterator + insert(const_iterator, _Tp&&) + { __throw_bad_alloc(); } + + constexpr iterator + insert(const_iterator, size_type __n, const _Tp&) + { + if (__n != 0) + __throw_bad_alloc(); + return begin(); + } + + template<typename _InputIterator> + constexpr iterator + insert(const_iterator, _InputIterator __first, _InputIterator __last) + { + if (__first != __last) + __throw_bad_alloc(); + return begin(); + } + + template<__detail::__container_compatible_range<_Tp> _Rg> + constexpr iterator + insert_range(const_iterator, _Rg&& __rg) + { + if (ranges::begin(__rg) != ranges::end(__rg)) + __throw_bad_alloc(); + return begin(); + } + + constexpr iterator + insert(const_iterator, initializer_list<_Tp> __il) + { + if (__il.size() != 0) + __throw_bad_alloc(); + return begin(); + } + + [[noreturn]] + constexpr iterator + erase(const_iterator) + { __builtin_trap(); } + + constexpr iterator + erase(const_iterator __first, const_iterator __last) + { + __glibcxx_assert(__first == __last); + return begin(); + } + + constexpr void + swap(inplace_vector& __x) + noexcept + { } + + constexpr void + clear() noexcept + { } + + constexpr friend bool + operator==(const inplace_vector&, const inplace_vector&) + { return true; } + + constexpr friend auto + operator<=>(const inplace_vector&, const inplace_vector&) + requires requires (const _Tp __t) { + { __t < __t } -> __detail::__boolean_testable; + } + { return std::strong_ordering::equal; } + + // n.b. there is not explicit wording requiring that swap for inplace_vector, + // with zero size, works even if element type is not swappable. However given + // that move operations are required to be present and trivial, it makes sense + // to support them. + constexpr friend void + swap(inplace_vector&, inplace_vector&) noexcept + { } + }; + +_GLIBCXX_END_NAMESPACE_CONTAINER + + template<typename _Tp, size_t _Nm, typename _Predicate> + constexpr size_t + erase_if(_GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __cont, + _Predicate __pred) + { + if constexpr (_Nm != 0) + { + const auto __osz = __cont.size(); + const auto __end = __cont.end(); + auto __removed = std::__remove_if(__cont.begin(), __end, + std::move(__pred)); + if (__removed != __end) + { + __cont.erase(__removed, __end); + return __osz - __cont.size(); + } + } + + return 0; + } + + template<typename _Tp, size_t _Nm, typename _Up = _Tp> + constexpr size_t + erase(_GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __cont, const _Up& __value) + { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#ifdef _GLIBCXX_DEBUG +# include <debug/inplace_vector> +#endif + +#endif // __glibcxx_inplace_vector +#endif // _GLIBCXX_INPLACE_VECTOR diff --git a/libstdc++-v3/include/std/istream b/libstdc++-v3/include/std/istream index d5bb187..ea232a7 100644 --- a/libstdc++-v3/include/std/istream +++ b/libstdc++-v3/include/std/istream @@ -42,6 +42,10 @@ #include <ios> #include <ostream> +#if __cplusplus > 202302L +#include <concepts> +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -537,7 +541,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * is extracted); note that this condition will never occur if * @a __delim equals @c traits::eof(). * - * NB: Provide three overloads, instead of the single function + * NB: Provide four overloads, instead of the single function * (with defaults) mandated by the Standard: this leads to a * better performing implementation, while still conforming to * the Standard. @@ -551,6 +555,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __istream_type& ignore(); +#if __cplusplus > 202302L + [[__gnu__::__always_inline__]] + __istream_type& + ignore(streamsize __n, char __delim) requires same_as<_CharT, char> + { return ignore(__n, traits_type::to_int_type(__delim)); } +#endif + /** * @brief Looking ahead in the stream * @return The next character, or eof(). diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch index cf64854..df126c6 100644 --- a/libstdc++-v3/include/std/latch +++ b/libstdc++-v3/include/std/latch @@ -41,7 +41,7 @@ #ifdef __cpp_lib_latch // C++ >= 20 && atomic_wait #include <bits/atomic_base.h> #include <ext/numeric_traits.h> -#include <utility> // cmp_equal, cmp_less_equal, etc. +#include <bits/intcmp.h> // cmp_equal, cmp_less_equal, etc. namespace std _GLIBCXX_VISIBILITY(default) { @@ -62,7 +62,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr explicit latch(ptrdiff_t __expected) noexcept - : _M_a(__expected) + : _M_counter(__expected) { __glibcxx_assert(__expected >= 0 && __expected <= max()); } ~latch() = default; @@ -74,35 +74,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION count_down(ptrdiff_t __update = 1) { __glibcxx_assert(__update >= 0 && __update <= max()); - auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, + auto const __old = __atomic_impl::fetch_sub(&_M_counter, __update, memory_order::release); if (std::cmp_equal(__old, __update)) - __atomic_impl::notify_all(&_M_a); + __atomic_impl::notify_all(&_M_counter); else __glibcxx_assert(std::cmp_less(__update, __old)); } _GLIBCXX_ALWAYS_INLINE bool try_wait() const noexcept - { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; } + { return __atomic_impl::load(&_M_counter, memory_order::acquire) == 0; } _GLIBCXX_ALWAYS_INLINE void wait() const noexcept { - auto const __pred = [this] { return this->try_wait(); }; - std::__atomic_wait_address(&_M_a, __pred); + auto const __vfn = [this] { + return __atomic_impl::load(&_M_counter, memory_order::acquire); + }; + auto const __pred = [](__detail::__platform_wait_t __v) { + return __v == 0; + }; + std::__atomic_wait_address(&_M_counter, __pred, __vfn); } _GLIBCXX_ALWAYS_INLINE void arrive_and_wait(ptrdiff_t __update = 1) noexcept { - count_down(__update); - wait(); + // The standard specifies this functions as count_down(update); wait(); + // but we combine those two calls into one and avoid the wait() if we + // know the counter reached zero. + + __glibcxx_assert(__update >= 0 && __update <= max()); + // Use acq_rel here because an omitted wait() would have used acquire: + auto const __old = __atomic_impl::fetch_sub(&_M_counter, __update, + memory_order::acq_rel); + if (std::cmp_equal(__old, __update)) + __atomic_impl::notify_all(&_M_counter); + else + { + __glibcxx_assert(std::cmp_less(__update, __old)); + wait(); + } } private: alignas(__detail::__platform_wait_alignment) - __detail::__platform_wait_t _M_a; + __detail::__platform_wait_t _M_counter; }; _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/std/limits b/libstdc++-v3/include/std/limits index 2331c25..49ce7c9 100644 --- a/libstdc++-v3/include/std/limits +++ b/libstdc++-v3/include/std/limits @@ -1639,7 +1639,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __INT_N_U201103(TYPE) #endif -#if !defined(__STRICT_ANSI__) #ifdef __GLIBCXX_TYPE_INT_N_0 __INT_N(__GLIBCXX_TYPE_INT_N_0, __GLIBCXX_BITSIZE_INT_N_0, __INT_N_201103 (__GLIBCXX_TYPE_INT_N_0), @@ -1661,7 +1660,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __INT_N_U201103 (__GLIBCXX_TYPE_INT_N_3)) #endif -#elif defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ +#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ __INT_N(__int128, 128, __INT_N_201103 (__int128), __INT_N_U201103 (__int128)) @@ -2129,7 +2128,7 @@ __glibcxx_float_n(128) static _GLIBCXX_USE_CONSTEXPR int digits = 113; static _GLIBCXX_USE_CONSTEXPR int digits10 = 33; #if __cplusplus >= 201103L - static constexpr int max_digits10 = 35; + static constexpr int max_digits10 = 36; #endif static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; static _GLIBCXX_USE_CONSTEXPR bool is_integer = false; diff --git a/libstdc++-v3/include/std/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..dc0aa4f --- /dev/null +++ b/libstdc++-v3/include/std/mdspan @@ -0,0 +1,3399 @@ +// <mdspan> -*- C++ -*- + +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file mdspan + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_MDSPAN +#define _GLIBCXX_MDSPAN 1 + +#ifdef _GLIBCXX_SYSHDR +#pragma GCC system_header +#endif + +#include <span> +#include <array> +#include <type_traits> +#include <utility> + +#define __glibcxx_want_mdspan +#define __glibcxx_want_aligned_accessor +#define __glibcxx_want_submdspan +#include <bits/version.h> + +#if __glibcxx_aligned_accessor +#include <bits/align.h> +#endif + +#if __glibcxx_submdspan +#include <tuple> +#endif + + +#ifdef __glibcxx_mdspan + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + namespace __mdspan + { + consteval bool + __all_static(std::span<const size_t> __extents) + { + for(auto __ext : __extents) + if (__ext == dynamic_extent) + return false; + return true; + } + + consteval bool + __all_dynamic(std::span<const size_t> __extents) + { + for(auto __ext : __extents) + if (__ext != dynamic_extent) + return false; + return true; + } + + template<typename _IndexType, typename _OIndexType> + constexpr _IndexType + __index_type_cast(_OIndexType&& __other) + { + if constexpr (std::is_integral_v<_OIndexType>) + { + constexpr _IndexType __index_type_max + = __gnu_cxx::__int_traits<_IndexType>::__max; + constexpr _OIndexType __oindex_type_max + = __gnu_cxx::__int_traits<_OIndexType>::__max; + + if constexpr (__index_type_max < __oindex_type_max) + __glibcxx_assert(cmp_less_equal(__other, __index_type_max)); + + if constexpr (std::is_signed_v<_OIndexType>) + __glibcxx_assert(__other >= 0); + return static_cast<_IndexType>(__other); + } + else + { + auto __ret = static_cast<_IndexType>(std::move(__other)); + if constexpr (std::is_signed_v<_IndexType>) + __glibcxx_assert(__ret >= 0); + return __ret; + } + } + + template<array _Extents> + class _StaticExtents + { + public: + static constexpr size_t _S_rank = _Extents.size(); + + // For __r in [0, _S_rank], _S_dynamic_index(__r) is the number + // of dynamic extents up to (and not including) __r. + // + // If __r is the index of a dynamic extent, then + // _S_dynamic_index[__r] is the index of that extent in + // _M_dyn_exts. + static constexpr size_t + _S_dynamic_index(size_t __r) noexcept + { return _S_dynamic_index_data[__r]; } + + static constexpr auto _S_dynamic_index_data = [] consteval + { + array<size_t, _S_rank+1> __ret; + size_t __dyn = 0; + for (size_t __i = 0; __i < _S_rank; ++__i) + { + __ret[__i] = __dyn; + __dyn += (_Extents[__i] == dynamic_extent); + } + __ret[_S_rank] = __dyn; + return __ret; + }(); + + static constexpr size_t _S_rank_dynamic = _S_dynamic_index(_S_rank); + + // For __r in [0, _S_rank_dynamic), _S_dynamic_index_inv(__r) is the + // index of the __r-th dynamic extent in _Extents. + static constexpr size_t + _S_dynamic_index_inv(size_t __r) noexcept + { return _S_dynamic_index_inv_data[__r]; } + + static constexpr auto _S_dynamic_index_inv_data = [] consteval + { + array<size_t, _S_rank_dynamic> __ret; + for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i) + if (_Extents[__i] == dynamic_extent) + __ret[__r++] = __i; + return __ret; + }(); + + static constexpr size_t + _S_static_extent(size_t __r) noexcept + { return _Extents[__r]; } + }; + + template<array _Extents> + requires (__all_dynamic<_Extents>()) + class _StaticExtents<_Extents> + { + public: + static constexpr size_t _S_rank = _Extents.size(); + + static constexpr size_t + _S_dynamic_index(size_t __r) noexcept + { return __r; } + + static constexpr size_t _S_rank_dynamic = _S_rank; + + static constexpr size_t + _S_dynamic_index_inv(size_t __k) noexcept + { return __k; } + + static constexpr size_t + _S_static_extent(size_t) noexcept + { return dynamic_extent; } + }; + + template<typename _IndexType, array _Extents> + class _ExtentsStorage : public _StaticExtents<_Extents> + { + private: + using _Base = _StaticExtents<_Extents>; + + public: + using _Base::_S_rank; + using _Base::_S_rank_dynamic; + using _Base::_S_dynamic_index; + using _Base::_S_dynamic_index_inv; + using _Base::_S_static_extent; + + static constexpr bool + _S_is_dynamic(size_t __r) noexcept + { + if constexpr (__all_static(_Extents)) + return false; + else if constexpr (__all_dynamic(_Extents)) + return true; + else + return _Extents[__r] == dynamic_extent; + } + + template<typename _OIndexType> + static constexpr _IndexType + _S_int_cast(const _OIndexType& __other) noexcept + { return _IndexType(__other); } + + constexpr _IndexType + _M_extent(size_t __r) const noexcept + { + if (_S_is_dynamic(__r)) + return _M_dyn_exts[_S_dynamic_index(__r)]; + else + return _S_static_extent(__r); + } + + template<size_t _OtherRank, typename _GetOtherExtent> + static constexpr bool + _S_is_compatible_extents(_GetOtherExtent __get_extent) noexcept + { + if constexpr (_OtherRank == _S_rank) + for (size_t __i = 0; __i < _S_rank; ++__i) + if (!_S_is_dynamic(__i) + && !cmp_equal(_Extents[__i], _S_int_cast(__get_extent(__i)))) + return false; + return true; + } + + template<size_t _OtherRank, typename _GetOtherExtent> + constexpr void + _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept + { + __glibcxx_assert(_S_is_compatible_extents<_OtherRank>(__get_extent)); + for (size_t __i = 0; __i < _S_rank_dynamic; ++__i) + { + size_t __di = __i; + if constexpr (_OtherRank != _S_rank_dynamic) + __di = _S_dynamic_index_inv(__i); + _M_dyn_exts[__i] = _S_int_cast(__get_extent(__di)); + } + } + + constexpr + _ExtentsStorage() noexcept = default; + + template<typename _OIndexType, array _OExtents> + constexpr + _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>& + __other) noexcept + { + _M_init_dynamic_extents<_S_rank>([&__other](size_t __i) + { return __other._M_extent(__i); }); + } + + template<typename _OIndexType, size_t _Nm> + constexpr + _ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept + { + _M_init_dynamic_extents<_Nm>( + [&__exts](size_t __i) -> const _OIndexType& + { return __exts[__i]; }); + } + + static constexpr const array<size_t, _S_rank>& + _S_static_extents() noexcept + { return _Extents; } + + constexpr span<const _IndexType> + _M_dynamic_extents(size_t __begin, size_t __end) const noexcept + requires (_Extents.size() > 0) + { + return {_M_dyn_exts + _S_dynamic_index(__begin), + _S_dynamic_index(__end) - _S_dynamic_index(__begin)}; + } + + private: + using _Storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type; + [[no_unique_address]] _Storage _M_dyn_exts{}; + }; + + template<typename _OIndexType, typename _SIndexType> + concept __valid_index_type = + is_convertible_v<_OIndexType, _SIndexType> && + is_nothrow_constructible_v<_SIndexType, _OIndexType>; + + template<size_t _Extent, typename _IndexType> + concept + __valid_static_extent = _Extent == dynamic_extent + || _Extent <= __gnu_cxx::__int_traits<_IndexType>::__max; + + template<typename _Extents> + constexpr const array<size_t, _Extents::rank()>& + __static_extents() noexcept + { return _Extents::_Storage::_S_static_extents(); } + + template<typename _Extents> + constexpr span<const size_t> + __static_extents(size_t __begin, size_t __end) noexcept + { + const auto& __sta_exts = __static_extents<_Extents>(); + return span<const size_t>(__sta_exts.data() + __begin, __end - __begin); + } + + // Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n (exclusive) + template<array _Extents> + constexpr auto __fwd_partial_prods = [] consteval + { + constexpr size_t __rank = _Extents.size(); + std::array<size_t, __rank> __ret; + size_t __prod = 1; + for (size_t __r = 0; __r < __rank; ++__r) + { + __ret[__r] = __prod; + if (size_t __ext = _Extents[__r]; __ext != dynamic_extent) + __prod *= __ext; + } + return __ret; + }(); + + // Pre-compute: \prod_{i = r+1}^{n-1} _Extents[i] + template<array _Extents> + constexpr auto __rev_partial_prods = [] consteval + { + constexpr size_t __rank = _Extents.size(); + std::array<size_t, __rank> __ret; + size_t __prod = 1; + for (size_t __r = __rank; __r > 0; --__r) + { + __ret[__r - 1] = __prod; + if (size_t __ext = _Extents[__r - 1]; __ext != dynamic_extent) + __prod *= __ext; + } + return __ret; + }(); + + template<typename _Extents> + constexpr span<const typename _Extents::index_type> + __dynamic_extents(const _Extents& __exts, size_t __begin = 0, + size_t __end = _Extents::rank()) noexcept + { return __exts._M_exts._M_dynamic_extents(__begin, __end); } + } + +#if __glibcxx_submdspan + struct full_extent_t + { + explicit full_extent_t() = default; + }; + + inline constexpr full_extent_t full_extent{}; + + template<typename _OffsetType, typename _ExtentType, typename _StrideType> + struct strided_slice + { + static_assert(__is_signed_or_unsigned_integer<_OffsetType>::value + || __detail::__integral_constant_like<_OffsetType>); + static_assert(__is_signed_or_unsigned_integer<_ExtentType>::value + || __detail::__integral_constant_like<_ExtentType>); + static_assert(__is_signed_or_unsigned_integer<_StrideType>::value + || __detail::__integral_constant_like<_StrideType>); + + using offset_type = _OffsetType; + using extent_type = _ExtentType; + using stride_type = _StrideType; + + [[no_unique_address]] offset_type offset{}; + [[no_unique_address]] extent_type extent{}; + [[no_unique_address]] stride_type stride{}; + }; + + template<typename _Mapping> + struct submdspan_mapping_result + { + [[no_unique_address]] _Mapping mapping = _Mapping(); + size_t offset{}; + }; + + template<typename _Tp> + constexpr bool __is_submdspan_mapping_result = false; + + template<typename _Mapping> + constexpr bool __is_submdspan_mapping_result<submdspan_mapping_result<_Mapping>> = true; + + template<typename _Mapping> + concept __submdspan_mapping_result = __is_submdspan_mapping_result<_Mapping>; + +#endif // __glibcxx_submdspan + + template<typename _IndexType, size_t... _Extents> + class extents + { + static_assert(__is_signed_or_unsigned_integer<_IndexType>::value, + "IndexType must be a signed or unsigned integer type"); + static_assert( + (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...), + "Extents must either be dynamic or representable as IndexType"); + + using _Storage = __mdspan::_ExtentsStorage< + _IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>; + [[no_unique_address]] _Storage _M_exts; + + public: + using index_type = _IndexType; + using size_type = make_unsigned_t<index_type>; + using rank_type = size_t; + + static constexpr rank_type + rank() noexcept { return _Storage::_S_rank; } + + static constexpr rank_type + rank_dynamic() noexcept { return _Storage::_S_rank_dynamic; } + + static constexpr size_t + static_extent(rank_type __r) noexcept + { + __glibcxx_assert(__r < rank()); + if constexpr (rank() == 0) + __builtin_trap(); + else + return _Storage::_S_static_extent(__r); + } + + constexpr index_type + extent(rank_type __r) const noexcept + { + __glibcxx_assert(__r < rank()); + if constexpr (rank() == 0) + __builtin_trap(); + else + return _M_exts._M_extent(__r); + } + + constexpr + extents() noexcept = default; + + private: + static consteval bool + _S_is_less_dynamic(size_t __ext, size_t __oext) + { return (__ext != dynamic_extent) && (__oext == dynamic_extent); } + + template<typename _OIndexType, size_t... _OExtents> + static consteval bool + _S_ctor_explicit() + { + return (_S_is_less_dynamic(_Extents, _OExtents) || ...) + || (__gnu_cxx::__int_traits<index_type>::__max + < __gnu_cxx::__int_traits<_OIndexType>::__max); + } + + template<size_t... _OExtents> + static consteval bool + _S_is_compatible_extents() + { + if constexpr (sizeof...(_OExtents) != rank()) + return false; + else + return ((_OExtents == dynamic_extent || _Extents == dynamic_extent + || _OExtents == _Extents) && ...); + } + + public: + template<typename _OIndexType, size_t... _OExtents> + requires (_S_is_compatible_extents<_OExtents...>()) + constexpr explicit(_S_ctor_explicit<_OIndexType, _OExtents...>()) + extents(const extents<_OIndexType, _OExtents...>& __other) noexcept + : _M_exts(__other._M_exts) + { } + + template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> + requires (sizeof...(_OIndexTypes) == rank() + || sizeof...(_OIndexTypes) == rank_dynamic()) + constexpr explicit extents(_OIndexTypes... __exts) noexcept + : _M_exts(span<const _IndexType, sizeof...(_OIndexTypes)>( + initializer_list{static_cast<_IndexType>(std::move(__exts))...})) + { } + + template<typename _OIndexType, size_t _Nm> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + && (_Nm == rank() || _Nm == rank_dynamic()) + constexpr explicit(_Nm != rank_dynamic()) + extents(span<_OIndexType, _Nm> __exts) noexcept + : _M_exts(span<const _OIndexType, _Nm>(__exts)) + { } + + template<typename _OIndexType, size_t _Nm> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + && (_Nm == rank() || _Nm == rank_dynamic()) + constexpr explicit(_Nm != rank_dynamic()) + extents(const array<_OIndexType, _Nm>& __exts) noexcept + : _M_exts(span<const _OIndexType, _Nm>(__exts)) + { } + + template<typename _OIndexType, size_t... _OExtents> + friend constexpr bool + operator==(const extents& __self, + const extents<_OIndexType, _OExtents...>& __other) noexcept + { + if constexpr (!_S_is_compatible_extents<_OExtents...>()) + return false; + else + { + auto __impl = [&__self, &__other]<size_t... _Counts>( + index_sequence<_Counts...>) + { return (cmp_equal(__self.extent(_Counts), + __other.extent(_Counts)) && ...); }; + return __impl(make_index_sequence<__self.rank()>()); + } + } + + private: + friend constexpr const array<size_t, rank()>& + __mdspan::__static_extents<extents>() noexcept; + + friend constexpr span<const index_type> + __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t) + noexcept; + + template<typename _OIndexType, size_t... _OExtents> + friend class extents; + }; + + namespace __mdspan + { + template<typename _Tp, size_t _Nm> + constexpr bool + __contains_zero(span<_Tp, _Nm> __exts) noexcept + { + for (size_t __i = 0; __i < __exts.size(); ++__i) + if (__exts[__i] == 0) + return true; + return false; + } + + template<typename _Tp, size_t _Nm> + consteval bool + __contains_zero(const array<_Tp, _Nm>& __exts) noexcept + { return __contains_zero(span<const _Tp>(__exts)); } + + template<typename _Extents> + constexpr bool + __empty(const _Extents& __exts) noexcept + { + if constexpr (__contains_zero(__static_extents<_Extents>())) + return true; + else if constexpr (_Extents::rank_dynamic() > 0) + return __contains_zero(__dynamic_extents(__exts)); + else + return false; + } + + template<typename _Extents> + constexpr typename _Extents::index_type + __extents_prod(const _Extents& __exts, size_t __sta_prod, size_t __begin, + size_t __end) noexcept + { + if (__sta_prod == 0) + return 0; + + size_t __ret = __sta_prod; + if constexpr (_Extents::rank_dynamic() > 0) + for (auto __factor : __dynamic_extents(__exts, __begin, __end)) + __ret *= size_t(__factor); + return static_cast<typename _Extents::index_type>(__ret); + } + + // Preconditions: _r < _Extents::rank() + template<typename _Extents> + constexpr typename _Extents::index_type + __fwd_prod(const _Extents& __exts, size_t __begin, size_t __end) noexcept + { + size_t __sta_prod = [__begin, __end] { + span<const size_t> __sta_exts + = __static_extents<_Extents>(__begin, __end); + size_t __ret = 1; + for(auto __ext : __sta_exts) + if (__ext != dynamic_extent) + __ret *= __ext; + return __ret; + }(); + return __extents_prod(__exts, __sta_prod, __begin, __end); + } + + template<typename _Extents> + constexpr typename _Extents::index_type + __fwd_prod(const _Extents& __exts, size_t __r) noexcept + { + constexpr size_t __rank = _Extents::rank(); + constexpr auto& __sta_exts = __static_extents<_Extents>(); + if constexpr (__rank == 1) + return 1; + else if constexpr (__rank == 2) + return __r == 0 ? 1 : __exts.extent(0); + else if constexpr (__all_dynamic(std::span(__sta_exts).first(__rank-1))) + return __extents_prod(__exts, 1, 0, __r); + else + { + size_t __sta_prod = __fwd_partial_prods<__sta_exts>[__r]; + return __extents_prod(__exts, __sta_prod, 0, __r); + } + } + + template<typename _IndexType, size_t _Nm> + consteval _IndexType + __fwd_prod(span<const _IndexType, _Nm> __values) + { + _IndexType __ret = 1; + for(auto __value : __values) + __ret *= __value; + return __ret; + } + + // Preconditions: _r < _Extents::rank() + template<typename _Extents> + constexpr typename _Extents::index_type + __rev_prod(const _Extents& __exts, size_t __r) noexcept + { + constexpr size_t __rank = _Extents::rank(); + constexpr auto& __sta_exts = __static_extents<_Extents>(); + if constexpr (__rank == 1) + return 1; + else if constexpr (__rank == 2) + return __r == 0 ? __exts.extent(1) : 1; + else if constexpr (__all_dynamic(std::span(__sta_exts).last(__rank-1))) + return __extents_prod(__exts, 1, __r + 1, __rank); + else + { + size_t __sta_prod = __rev_partial_prods<__sta_exts>[__r]; + return __extents_prod(__exts, __sta_prod, __r + 1, __rank); + } + } + + template<typename _Extents> + constexpr typename _Extents::index_type + __size(const _Extents& __exts) noexcept + { + constexpr size_t __sta_prod = [] { + span<const size_t> __sta_exts = __static_extents<_Extents>(); + size_t __ret = 1; + for(auto __ext : __sta_exts) + if (__ext != dynamic_extent) + __ret *= __ext; + return __ret; + }(); + return __extents_prod(__exts, __sta_prod, 0, _Extents::rank()); + } + + template<typename _IndexType, size_t... _Counts> + auto __build_dextents_type(integer_sequence<size_t, _Counts...>) + -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>; + } + + template<typename _IndexType, size_t _Rank> + using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>( + make_index_sequence<_Rank>())); + +#if __glibcxx_mdspan >= 202406L + template<size_t _Rank, typename _IndexType = size_t> + using dims = dextents<_IndexType, _Rank>; +#endif + + template<typename... _Integrals> + requires (is_convertible_v<_Integrals, size_t> && ...) + explicit extents(_Integrals...) -> + extents<size_t, __detail::__maybe_static_ext<_Integrals>...>; + + struct layout_left + { + template<typename _Extents> + class mapping; + }; + + struct layout_right + { + template<typename _Extents> + class mapping; + }; + + struct layout_stride + { + template<typename _Extents> + class mapping; + }; + +#ifdef __glibcxx_padded_layouts + template<size_t _PaddingValue> + struct layout_left_padded + { + template<typename _Extents> + class mapping; + }; + + template<size_t _PaddingValue> + struct layout_right_padded + { + template<typename _Extents> + class mapping; + }; +#endif + + namespace __mdspan + { + template<typename _Tp> + constexpr bool __is_extents = false; + + template<typename _IndexType, size_t... _Extents> + constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true; + + template<typename _Extents, typename... _Indices> + constexpr typename _Extents::index_type + __linear_index_left(const _Extents& __exts, _Indices... __indices) + noexcept + { + using _IndexType = typename _Extents::index_type; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + _IndexType __mult = 1; + auto __update = [&, __pos = 0u](_IndexType __idx) mutable + { + _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __exts.extent(__pos))); + __res += __idx * __mult; + __mult *= __exts.extent(__pos); + ++__pos; + }; + (__update(__indices), ...); + } + return __res; + } + + template<typename _IndexType> + consteval _IndexType + __static_quotient(std::span<const size_t> __sta_exts, + _IndexType __nom = __gnu_cxx::__int_traits<_IndexType>::__max) + { + for (auto __factor : __sta_exts) + { + if (__factor != dynamic_extent) + __nom /= _IndexType(__factor); + if (__nom == 0) + break; + } + return __nom; + } + + template<typename _Extents, + typename _IndexType = typename _Extents::index_type> + requires __is_extents<_Extents> + consteval _IndexType + __static_quotient(_IndexType __nom + = __gnu_cxx::__int_traits<_IndexType>::__max) + { + std::span<const size_t> __sta_exts = __static_extents<_Extents>(); + return __static_quotient<_IndexType>(__sta_exts, __nom); + } + + template<typename _Extents> + constexpr bool + __is_representable_extents(const _Extents& __exts) noexcept + { + using _IndexType = _Extents::index_type; + + if constexpr (__contains_zero(__static_extents<_Extents>())) + return true; + else + { + constexpr auto __sta_quo = __static_quotient<_Extents>(); + if constexpr (_Extents::rank_dynamic() == 0) + return __sta_quo != 0; + else + { + auto __dyn_exts = __dynamic_extents(__exts); + if (__contains_zero(__dyn_exts)) + return true; + + if constexpr (__sta_quo == 0) + return false; + else + { + auto __dyn_quo = _IndexType(__sta_quo); + for (auto __factor : __dyn_exts) + { + __dyn_quo /= __factor; + if (__dyn_quo == 0) + return false; + } + return true; + } + } + } + } + + template<typename _Extents, typename _IndexType> + concept __representable_size = _Extents::rank_dynamic() != 0 + || __contains_zero(__static_extents<_Extents>()) + || (__static_quotient<_Extents, _IndexType>() != 0); + + template<typename _Layout, typename _Mapping> + concept __mapping_of = + is_same_v<typename _Layout::template mapping< + typename _Mapping::extents_type>, + _Mapping>; + + template<template<size_t> typename _Layout, typename _Mapping> + concept __padded_mapping_of = __mapping_of< + _Layout<_Mapping::padding_value>, _Mapping>; + +#ifdef __glibcxx_padded_layouts + template<typename _Mapping> + constexpr bool __is_left_padded_mapping = __padded_mapping_of< + layout_left_padded, _Mapping>; + + template<typename _Mapping> + constexpr bool __is_right_padded_mapping = __padded_mapping_of< + layout_right_padded, _Mapping>; + + template<typename _Mapping> + constexpr bool __is_padded_mapping = __is_left_padded_mapping<_Mapping> + || __is_right_padded_mapping<_Mapping>; +#endif + + template<typename _PaddedMapping> + consteval size_t + __get_static_stride() + { return _PaddedMapping::_PaddedStorage::_S_static_stride; } + + template<typename _Mapping> + concept __standardized_mapping = __mapping_of<layout_left, _Mapping> + || __mapping_of<layout_right, _Mapping> + || __mapping_of<layout_stride, _Mapping> +#ifdef __glibcxx_padded_layouts + || __is_left_padded_mapping<_Mapping> + || __is_right_padded_mapping<_Mapping> +#endif + ; + + // A tag type to create internal ctors. + class __internal_ctor + { }; + + template<typename _Mapping> + constexpr typename _Mapping::index_type + __offset(const _Mapping& __m) noexcept + { + using _IndexType = typename _Mapping::index_type; + constexpr auto __rank = _Mapping::extents_type::rank(); + + if constexpr (__standardized_mapping<_Mapping>) + return 0; + else if (__empty(__m.extents())) + return 0; + else + { + auto __impl = [&__m]<size_t... _Counts>(index_sequence<_Counts...>) + { return __m(((void) _Counts, _IndexType(0))...); }; + return __impl(make_index_sequence<__rank>()); + } + } + +#ifdef __glibcxx_submdspan + template<typename _Tp> + constexpr bool __is_strided_slice = false; + + template<typename _OffsetType, typename _ExtentType, typename _StrideType> + constexpr bool __is_strided_slice<strided_slice<_OffsetType, + _ExtentType, _StrideType>> = true; + + template<typename _IndexType, typename _OIndexType> + consteval bool + __is_representable_integer(_OIndexType __value) + { + constexpr auto __min = __gnu_cxx::__int_traits<_IndexType>::__min; + constexpr auto __max = __gnu_cxx::__int_traits<_IndexType>::__max; + return std::cmp_less_equal(__min, __value) + && std::cmp_less_equal(__value, __max); + } + + template<typename _Tp> + constexpr bool __is_constant_wrapper = false; + + template<_CwFixedValue _Xv, typename _Tp> + constexpr bool __is_constant_wrapper<constant_wrapper<_Xv, _Tp>> + = true; + + template<size_t _Index, typename _Extents> + constexpr auto + __extract_extent(const _Extents& __exts) + { + using _IndexType = typename _Extents::index_type; + return extents<_IndexType, _Extents::static_extent(_Index)>{ + __exts.extent(_Index)}; + } + + template<typename _Slice, typename _IndexType> + concept __acceptable_slice_type = same_as<_Slice, full_extent_t> + || same_as<_Slice, _IndexType> || __is_constant_wrapper<_Slice> + || __is_strided_slice<_Slice>; + + template<typename _IndexType, typename... _Slices> + consteval auto + __subrank() + { + return (static_cast<size_t>(!convertible_to<_Slices, _IndexType>) + + ... + 0); + } + + template<typename _IndexType, typename... _Slices> + consteval auto + __inv_map_rank() + { + constexpr auto __rank = sizeof...(_Slices); + constexpr auto __sub_rank = __subrank<_IndexType, _Slices...>(); + auto __map = std::array<size_t, __sub_rank>{}; + auto __is_int_like = std::array<bool, __rank>{ + convertible_to<_Slices, _IndexType>...}; + + size_t __i = 0; + for (size_t __k = 0; __k < __rank; ++__k) + if (!__is_int_like[__k]) + __map[__i++] = __k; + return __map; + } + + template<typename _Slice> + constexpr auto + __slice_begin(_Slice __slice) + { + if constexpr (same_as<_Slice, full_extent_t>) + return 0; + else if constexpr (__is_strided_slice<_Slice>) + return __slice.offset; + else + return __slice; // collapsing slice + } + + template<typename _Mapping, typename... _Slices> + constexpr size_t + __suboffset(const _Mapping& __mapping, const _Slices&... __slices) + { + using _IndexType = typename _Mapping::index_type; + auto __any_past_the_end = [&]<size_t... _Is>(index_sequence<_Is...>) + { + auto __is_past_the_end = [](const auto& __slice, const auto& __ext) + { + using _Slice = remove_cvref_t<decltype(__slice)>; + if constexpr (is_convertible_v<_Slice, _IndexType>) + return false; + else if constexpr (same_as<_Slice, full_extent_t> + && __ext.static_extent(0) != 0 + && __ext.static_extent(0) != dynamic_extent) + return false; + else + return __mdspan::__slice_begin(__slice) == __ext.extent(0); + }; + + const auto& __exts = __mapping.extents(); + return ((__is_past_the_end(__slices...[_Is], + __mdspan::__extract_extent<_Is>(__exts))) || ...); + }; + + if constexpr ((same_as<_Slices, full_extent_t> && ...)) + return __mdspan::__offset(__mapping); + + if (__any_past_the_end(std::make_index_sequence<sizeof...(__slices)>())) + return __mapping.required_span_size(); + return __mapping(__mdspan::__slice_begin(__slices)...); + } + + template<typename _IndexType, size_t _Extent, typename _Slice> + consteval size_t + __static_slice_extent() + { + if constexpr (same_as<_Slice, full_extent_t>) + return _Extent; + else if constexpr (same_as<_Slice, constant_wrapper<_IndexType(0)>>) + return 0; + else if constexpr (__is_constant_wrapper<typename _Slice::extent_type> + && __is_constant_wrapper<typename _Slice::stride_type>) + return 1 + ((typename _Slice::extent_type{}) - 1) + / (typename _Slice::stride_type{}); + else + return dynamic_extent; + } + + template<size_t _K, typename _Extents, typename _Slice> + constexpr typename _Extents::index_type + __dynamic_slice_extent(const _Extents& __exts, _Slice __slice) + { + if constexpr (__is_strided_slice<_Slice>) + return __slice.extent == 0 ? 0 : 1 + (__slice.extent - 1) / __slice.stride; + else + return __exts.extent(_K); + } + + template<typename _IndexType, size_t... _Extents, typename... _Slices> + requires (sizeof...(_Slices) == sizeof...(_Extents)) + constexpr auto + __subextents(const extents<_IndexType, _Extents...>& __exts, + _Slices... __slices) + { + constexpr auto __inv_map = __mdspan::__inv_map_rank<_IndexType, _Slices...>(); + auto __impl = [&]<size_t... _Indices>(std::index_sequence<_Indices...>) + { + using _SubExts = extents<_IndexType, + __mdspan::__static_slice_extent<_IndexType, + _Extents...[__inv_map[_Indices]], + _Slices...[__inv_map[_Indices]]>()...>; + if constexpr (_SubExts::rank_dynamic() == 0) + return _SubExts{}; + else + { + using _StaticSubExtents = __mdspan::_StaticExtents< + __mdspan::__static_extents<_SubExts>()>; + auto __create = [&]<size_t... _Is>(std::index_sequence<_Is...>) + { + constexpr auto __slice_idx = [__inv_map](size_t __i) consteval + { + return __inv_map[_StaticSubExtents::_S_dynamic_index_inv(__i)]; + }; + + return _SubExts{__mdspan::__dynamic_slice_extent<__slice_idx(_Is)>( + __exts, __slices...[__slice_idx(_Is)])...}; + }; + constexpr auto __dyn_subrank = _SubExts::rank_dynamic(); + return __create(std::make_index_sequence<__dyn_subrank>()); + } + }; + + return __impl(std::make_index_sequence<__inv_map.size()>()); + } + + enum class _LayoutSide + { + __left, + __right, + __unknown + }; + + template<typename _Mapping> + consteval _LayoutSide + __mapping_side() + { + if constexpr (__is_left_padded_mapping<_Mapping> + || __mapping_of<layout_left, _Mapping>) + return _LayoutSide::__left; + if constexpr (__is_right_padded_mapping<_Mapping> + || __mapping_of<layout_right, _Mapping>) + return _LayoutSide::__right; + else + return _LayoutSide::__unknown; + } + + template<_LayoutSide _Side, size_t _Rank> + struct _StridesTrait + { + static constexpr const _LayoutSide _S_side = _Side; + + static constexpr size_t + _S_idx(size_t __k) noexcept + { + if constexpr (_Side == _LayoutSide::__left) + return __k; + else + return _Rank - 1 - __k; + } + + // Unifies the formulas for computing strides for padded and unpadded + // layouts. + template<typename _Mapping> + static constexpr typename _Mapping::index_type + _S_padded_extent(const _Mapping& __mapping, size_t __k) + { + if (__k == 0) + return __mapping.stride(_S_idx(1)); + else + return __mapping.extents().extent(_S_idx(__k)); + } + + template<typename _IndexType, typename... _Slices> + static consteval auto + _S_inv_map() + { + static_assert(_Side != _LayoutSide::__unknown); + auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>) + { + return __mdspan::__inv_map_rank<_IndexType, _Slices...[_S_idx(_Is)]...>(); + }; + return __impl(std::make_index_sequence<_Rank>()); + } + }; + + template<typename _SubExts, typename _Mapping, typename... _Slices> + constexpr auto + __substrides_generic(const _Mapping& __mapping, const _Slices&... __slices) + { + using _IndexType = typename _Mapping::index_type; + if constexpr (_SubExts::rank() == 0) + return array<_IndexType, _SubExts::rank()>{}; + else + { + auto __stride = [&__mapping](size_t __k, auto __slice) -> _IndexType + { + if constexpr (__is_strided_slice<decltype(__slice)>) + if (__slice.stride < __slice.extent) + return __mapping.stride(__k) * __slice.stride; + return __mapping.stride(__k); + }; + + auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>) + { + constexpr auto __inv_map + = __mdspan::__inv_map_rank<_IndexType, _Slices...>(); + return array<_IndexType, _SubExts::rank()>{ + __stride(__inv_map[_Is], __slices...[__inv_map[_Is]])...}; + }; + return __impl(std::make_index_sequence<_SubExts::rank()>()); + } + }; + + template<typename _SubExts, typename _Mapping, typename... _Slices> + constexpr auto + __substrides_standardized(const _Mapping& __mapping, + const _Slices&... __slices) + { + using _IndexType = typename _Mapping::index_type; + using _Trait = _StridesTrait<__mapping_side<_Mapping>(), + _Mapping::extents_type::rank()>; + using _SubTrait = _StridesTrait<__mapping_side<_Mapping>(), _SubExts::rank()>; + + constexpr size_t __sub_rank = _SubExts::rank(); + + std::array<_IndexType, __sub_rank> __ret; + if constexpr (__sub_rank > 0) + { + constexpr auto __inv_map + = _Trait::template _S_inv_map<_IndexType, _Slices...>(); + auto __loop = [&]<size_t... _Ks>(std::index_sequence<_Ks...>) + { + size_t __i0 = 0; + size_t __stride = 1; + auto __body = [&](size_t __k, auto __slice) + { + for (size_t __i = __i0; __i < __inv_map[__k]; ++__i) + __stride *= _Trait::_S_padded_extent(__mapping, __i); + + size_t __krev = _SubTrait::_S_idx(__k); + if constexpr (__is_strided_slice<decltype(__slice)>) + { + if (__slice.stride < __slice.extent) + __ret[__krev] = __stride * __slice.stride; + else + __ret[__krev] = __stride; + } + else + __ret[__krev] = __stride; + + __i0 = __inv_map[__k]; + }; + + ((__body(_Ks, __slices...[_Trait::_S_idx(__inv_map[_Ks])])),...); + }; + __loop(std::make_index_sequence<__sub_rank>()); + } + return __ret; + } + + + template<typename _SubExts, typename _Mapping, typename... _Slices> + constexpr auto + __substrides(const _Mapping& __mapping, const _Slices&... __slices) + { + if constexpr (__mdspan::__mapping_side<_Mapping>() == _LayoutSide::__unknown) + return __mdspan::__substrides_generic<_SubExts>(__mapping, __slices...); + else + return __mdspan::__substrides_standardized<_SubExts>(__mapping, __slices...); + } + + template<typename _Slice> + concept __is_unit_stride_slice = (__mdspan::__is_strided_slice<_Slice> + && __mdspan::__is_constant_wrapper<typename _Slice::stride_type> + && _Slice::stride_type::value == 1) + || std::same_as<_Slice, full_extent_t>; + + // These are (forced) exclusive categories: + // - full & collapsing: obvious, + // - unit_strided_slice: strided_slice{a, b, cw<1>}, but not `full`, + // - strided_slice: strided_slice{a, b, c} with c != cw<1>. + enum class _SliceKind + { + __strided_slice, + __unit_strided_slice, + __full, + __collapsing + }; + + template<typename _Slice> + consteval _SliceKind + __make_slice_kind() + { + if constexpr (std::same_as<_Slice, full_extent_t>) + return _SliceKind::__full; + else if constexpr (__mdspan::__is_strided_slice<_Slice>) + { + if constexpr (__mdspan::__is_unit_stride_slice<_Slice>) + return _SliceKind::__unit_strided_slice; + else + return _SliceKind::__strided_slice; + } + else + return _SliceKind::__collapsing; + } + + template<typename... _Slices> + consteval array<_SliceKind, sizeof...(_Slices)> + __make_slice_kind_array() + { + return array<_SliceKind, sizeof...(_Slices)>{ + __mdspan::__make_slice_kind<_Slices>()...}; + } + + // __block_size - 1 + // [full, ..., full, unit_slice , *] + consteval bool + __is_block(span<const _SliceKind> __slice_kinds, size_t __block_size) + { + if (__block_size == 0) + return false; + + if (__block_size > __slice_kinds.size()) + return false; + + for (size_t __i = 0; __i < __block_size - 1; ++__i) + if (__slice_kinds[__i] != _SliceKind::__full) + return false; + + auto __last = __slice_kinds[__block_size - 1]; + return __last == _SliceKind::__full + || __last == _SliceKind::__unit_strided_slice; + } + + // __u __u + __sub_rank-2 + // [unit_slice, i, ..., k, full, ..., full, unit_slice, *] + static consteval size_t + __padded_block_begin_generic(span<const _SliceKind> __slice_kinds, + size_t __sub_rank) + { + if (__slice_kinds[0] != _SliceKind::__full + && __slice_kinds[0] != _SliceKind::__unit_strided_slice) + return dynamic_extent; + else if (__slice_kinds.size() == 1) + return dynamic_extent; + else + { + size_t __u = 1; + while(__u < __slice_kinds.size() + && __slice_kinds[__u] == _SliceKind::__collapsing) + ++__u; + + if (__mdspan::__is_block(__slice_kinds.subspan(__u), __sub_rank -1)) + return __u; + return dynamic_extent; + } + } + + template<_LayoutSide _Side, size_t _Nm> + static consteval size_t + __padded_block_begin(span<const _SliceKind, _Nm> __slice_kinds, size_t __sub_rank) + { + if constexpr (_Side == _LayoutSide::__left) + return __mdspan::__padded_block_begin_generic(__slice_kinds, __sub_rank); + else + { + std::array<_SliceKind, _Nm> __rev_slices; + for(size_t __i = 0; __i < _Nm; ++__i) + __rev_slices[__i] = __slice_kinds[_Nm - 1 - __i]; + auto __rev_slice_kinds = span<const _SliceKind>(__rev_slices); + + auto __u = __mdspan::__padded_block_begin_generic(__rev_slice_kinds, + __sub_rank); + return __u == dynamic_extent ? dynamic_extent : _Nm - 1 - __u; + } + } + + template<_LayoutSide _Side, bool _Padded> + struct _SubMdspanMapping; + + template<> + struct _SubMdspanMapping<_LayoutSide::__left, false> + { + using _Layout = layout_left; + template<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>; + + template<typename _Mapping, size_t _Us> + static consteval size_t + _S_pad() + { + using _Extents = typename _Mapping::extents_type; + constexpr auto __sta_exts = __mdspan::__static_extents<_Extents>(0, _Us); + if constexpr (!__mdspan::__all_static(__sta_exts)) + return dynamic_extent; + else + return __mdspan::__fwd_prod(__sta_exts); + } + + template<size_t _Nm> + static consteval bool + _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, size_t __sub_rank) + { return __mdspan::__is_block(__slice_kinds, __sub_rank); } + }; + + template<> + struct _SubMdspanMapping<_LayoutSide::__left, true> + { + using _Layout = layout_left; + template<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>; + + template<typename _Mapping, size_t _Us> + static consteval size_t + _S_pad() + { + using _Extents = typename _Mapping::extents_type; + constexpr auto __sta_exts + = __mdspan::__static_extents<_Extents>(1, _Us); + constexpr auto __sta_padstride + = __mdspan::__get_static_stride<_Mapping>(); + if constexpr (__sta_padstride == dynamic_extent + || !__mdspan::__all_static(__sta_exts)) + return dynamic_extent; + else + return __sta_padstride * __mdspan::__fwd_prod(__sta_exts); + } + + template<size_t _Nm> + static consteval bool + _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, + size_t __sub_rank) + { + if (__sub_rank == 1) + return __slice_kinds[0] == _SliceKind::__unit_strided_slice + || __slice_kinds[0] == _SliceKind::__full; + else + return false; + } + }; + + template<> + struct _SubMdspanMapping<_LayoutSide::__right, false> + { + using _Layout = layout_right; + template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>; + + template<typename _Mapping, size_t _Us> + static consteval size_t + _S_pad() + { + using _Extents = typename _Mapping::extents_type; + constexpr auto __rank = _Extents::rank(); + constexpr auto __sta_exts + = __mdspan::__static_extents<_Extents>(_Us + 1, __rank); + if constexpr (!__mdspan::__all_static(__sta_exts)) + return dynamic_extent; + else + return __fwd_prod(__sta_exts); + } + + template<size_t _Nm> + static consteval bool + _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, + size_t __sub_rank) + { + auto __rev_slice_kinds = array<_SliceKind, _Nm>{}; + for(size_t __i = 0; __i < _Nm; ++__i) + __rev_slice_kinds[__i] = __slice_kinds[_Nm - 1 - __i]; + return __mdspan::__is_block(span(__rev_slice_kinds), __sub_rank); + } + }; + + template<> + struct _SubMdspanMapping<_LayoutSide::__right, true> + { + using _Layout = layout_right; + template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>; + + template<typename _Mapping, size_t _Us> + static consteval size_t + _S_pad() + { + using _Extents = typename _Mapping::extents_type; + constexpr auto __rank = _Extents::rank(); + constexpr auto __sta_exts + = __mdspan::__static_extents<_Extents>(_Us + 1, __rank - 1); + constexpr auto __sta_padstride + = __mdspan::__get_static_stride<_Mapping>(); + if constexpr (__sta_padstride == dynamic_extent + || !__mdspan::__all_static(__sta_exts)) + return dynamic_extent; + else + return __sta_padstride * __mdspan::__fwd_prod(__sta_exts); + } + + template<size_t _Nm> + static consteval bool + _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, + size_t __sub_rank) + { + if (__sub_rank == 1) + return __slice_kinds[_Nm - 1] == _SliceKind::__unit_strided_slice + || __slice_kinds[_Nm - 1] == _SliceKind::__full; + else + return false; + } + }; + + + template<typename _Mapping> + constexpr auto + __submdspan_mapping_impl(const _Mapping& __mapping) + { return submdspan_mapping_result{__mapping, 0}; } + + template<typename _Mapping, typename... _Slices> + requires (sizeof...(_Slices) > 0) + constexpr auto + __submdspan_mapping_impl(const _Mapping& __mapping, _Slices... __slices) + { + using _IndexType = typename _Mapping::index_type; + static_assert((__acceptable_slice_type<_Slices, _IndexType> && ...)); + + constexpr auto __side = __mdspan::__mapping_side<_Mapping>(); + constexpr auto __rank = sizeof...(_Slices); + using _Trait = _SubMdspanMapping<__side, __is_padded_mapping<_Mapping>>; + using _SliceView = span<const _SliceKind, __rank>; + + constexpr auto __slice_kinds = __mdspan::__make_slice_kind_array<_Slices...>(); + auto __offset = __mdspan::__suboffset(__mapping, __slices...); + auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...); + using _SubExts = decltype(__sub_exts); + constexpr auto __sub_rank = _SubExts::rank(); + if constexpr (__sub_rank == 0) + return submdspan_mapping_result{ + typename _Trait::_Layout::mapping(__sub_exts), __offset}; + else if constexpr (_Trait::_S_is_unpadded_submdspan( + _SliceView(__slice_kinds), __sub_rank)) + return submdspan_mapping_result{ + typename _Trait::_Layout::mapping(__sub_exts), __offset}; + else if constexpr ( + constexpr auto __u = __padded_block_begin<__side>( + _SliceView(__slice_kinds), __sub_rank); + __u != dynamic_extent) + { + constexpr auto __pad = _Trait::template _S_pad<_Mapping, __u>(); + using _Layout = typename _Trait::template _PaddedLayout<__pad>; + return submdspan_mapping_result{ + typename _Layout::mapping(__sub_exts, __mapping.stride(__u)), + __offset}; + } + else + { + auto __sub_strides + = __mdspan::__substrides<_SubExts>(__mapping, __slices...); + return submdspan_mapping_result{ + layout_stride::mapping(__sub_exts, __sub_strides), __offset}; + } + } +#endif // __glibcxx_submdspan + } + + template<typename _Extents> + class layout_left::mapping + { + public: + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_left; + + static_assert(__mdspan::__representable_size<extents_type, index_type>, + "The size of extents_type must be representable as index_type"); + + constexpr + mapping() noexcept = default; + + constexpr + mapping(const mapping&) noexcept = default; + + constexpr + mapping(const extents_type& __extents) noexcept + : _M_extents(__extents) + { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + template<typename _OExtents> + requires (extents_type::rank() <= 1) + && is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const layout_right::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + // noexcept for consistency with other layouts. + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(!(extents_type::rank() == 0 + && is_convertible_v<_OExtents, extents_type>)) + mapping(const layout_stride::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { __glibcxx_assert(*this == __other); } + +#if __glibcxx_padded_layouts + template<typename _LeftpadMapping> + requires __mdspan::__is_left_padded_mapping<_LeftpadMapping> + && is_constructible_v<extents_type, + typename _LeftpadMapping::extents_type> + constexpr + explicit(!is_convertible_v<typename _LeftpadMapping::extents_type, + extents_type>) + mapping(const _LeftpadMapping& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { + constexpr size_t __ostride_sta + = __mdspan::__get_static_stride<_LeftpadMapping>(); + + if constexpr (extents_type::rank() > 1) + { + if constexpr (extents_type::static_extent(0) != dynamic_extent + && __ostride_sta != dynamic_extent) + static_assert(extents_type::static_extent(0) == __ostride_sta); + else + __glibcxx_assert(__other.stride(1) + == __other.extents().extent(0)); + } + } +#endif // __glibcxx_padded_layouts + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_extents; } + + constexpr index_type + required_span_size() const noexcept + { return __mdspan::__size(_M_extents); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4314. Missing move in mdspan layout mapping::operator() + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == extents_type::rank()) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_left(_M_extents, + static_cast<index_type>(std::move(__indices))...); + } + + static constexpr bool + is_always_unique() noexcept { return true; } + + static constexpr bool + is_always_exhaustive() noexcept { return true; } + + static constexpr bool + is_always_strided() noexcept { return true; } + + static constexpr bool + is_unique() noexcept { return true; } + + static constexpr bool + is_exhaustive() noexcept { return true; } + + static constexpr bool + is_strided() noexcept { return true; } + + constexpr index_type + stride(rank_type __i) const noexcept + requires (extents_type::rank() > 0) + { + __glibcxx_assert(__i < extents_type::rank()); + return __mdspan::__fwd_prod(_M_extents, __i); + } + + template<typename _OExtents> + requires (extents_type::rank() == _OExtents::rank()) + friend constexpr bool + operator==(const mapping& __self, const mapping<_OExtents>& __other) + noexcept + { return __self.extents() == __other.extents(); } + + private: + template<typename _OExtents> + constexpr explicit + mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept + : _M_extents(__oexts) + { + static_assert(__mdspan::__representable_size<_OExtents, index_type>, + "The size of OtherExtents must be representable as index_type"); + __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); + } + +#if __glibcxx_submdspan + template<typename... _Slices> + requires (extents_type::rank() == sizeof...(_Slices)) + friend constexpr auto + submdspan_mapping(const mapping& __mapping, _Slices... __slices) + { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } +#endif // __glibcxx_submdspan + + [[no_unique_address]] extents_type _M_extents{}; + }; + + namespace __mdspan + { + template<typename _Extents, typename... _Indices> + constexpr typename _Extents::index_type + __linear_index_right(const _Extents& __exts, _Indices... __indices) + noexcept + { + using _IndexType = typename _Extents::index_type; + array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...}; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + _IndexType __mult = 1; + auto __update = [&, __pos = __exts.rank()](_IndexType) mutable + { + --__pos; + _GLIBCXX_DEBUG_ASSERT(cmp_less(__ind_arr[__pos], + __exts.extent(__pos))); + __res += __ind_arr[__pos] * __mult; + __mult *= __exts.extent(__pos); + }; + (__update(__indices), ...); + } + return __res; + } + } + + template<typename _Extents> + class layout_right::mapping + { + public: + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_right; + + static_assert(__mdspan::__representable_size<extents_type, index_type>, + "The size of extents_type must be representable as index_type"); + + constexpr + mapping() noexcept = default; + + constexpr + mapping(const mapping&) noexcept = default; + + constexpr + mapping(const extents_type& __extents) noexcept + : _M_extents(__extents) + { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + template<typename _OExtents> + requires (extents_type::rank() <= 1) + && is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const layout_left::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(!(extents_type::rank() == 0 + && is_convertible_v<_OExtents, extents_type>)) + mapping(const layout_stride::mapping<_OExtents>& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { __glibcxx_assert(*this == __other); } + +#if __glibcxx_padded_layouts + template<typename _RightPaddedMapping> + requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping> + && is_constructible_v<extents_type, + typename _RightPaddedMapping::extents_type> + constexpr + explicit(!is_convertible_v<typename _RightPaddedMapping::extents_type, + extents_type>) + mapping(const _RightPaddedMapping& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { + constexpr size_t __rank = extents_type::rank(); + constexpr size_t __ostride_sta + = __mdspan::__get_static_stride<_RightPaddedMapping>(); + + if constexpr (__rank > 1) + { + if constexpr (extents_type::static_extent(__rank - 1) != dynamic_extent + && __ostride_sta != dynamic_extent) + static_assert(extents_type::static_extent(__rank - 1) + == __ostride_sta); + else + __glibcxx_assert(__other.stride(__rank - 2) + == __other.extents().extent(__rank - 1)); + } + } +#endif + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_extents; } + + constexpr index_type + required_span_size() const noexcept + { return __mdspan::__size(_M_extents); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4314. Missing move in mdspan layout mapping::operator() + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == extents_type::rank()) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_right( + _M_extents, static_cast<index_type>(std::move(__indices))...); + } + + static constexpr bool + is_always_unique() noexcept + { return true; } + + static constexpr bool + is_always_exhaustive() noexcept + { return true; } + + static constexpr bool + is_always_strided() noexcept + { return true; } + + static constexpr bool + is_unique() noexcept + { return true; } + + static constexpr bool + is_exhaustive() noexcept + { return true; } + + static constexpr bool + is_strided() noexcept + { return true; } + + constexpr index_type + stride(rank_type __i) const noexcept + requires (extents_type::rank() > 0) + { + __glibcxx_assert(__i < extents_type::rank()); + return __mdspan::__rev_prod(_M_extents, __i); + } + + template<typename _OExtents> + requires (extents_type::rank() == _OExtents::rank()) + friend constexpr bool + operator==(const mapping& __self, const mapping<_OExtents>& __other) + noexcept + { return __self.extents() == __other.extents(); } + + private: + template<typename _OExtents> + constexpr explicit + mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept + : _M_extents(__oexts) + { + static_assert(__mdspan::__representable_size<_OExtents, index_type>, + "The size of OtherExtents must be representable as index_type"); + __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); + } + +#if __glibcxx_submdspan + template<typename... _Slices> + requires (extents_type::rank() == sizeof...(_Slices)) + friend constexpr auto + submdspan_mapping(const mapping& __mapping, _Slices... __slices) + { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } +#endif // __glibcxx_submdspan + + [[no_unique_address]] extents_type _M_extents{}; + }; + + namespace __mdspan + { + template<typename _Mp> + concept __mapping_alike = requires + { + requires __is_extents<typename _Mp::extents_type>; + { _Mp::is_always_strided() } -> same_as<bool>; + { _Mp::is_always_exhaustive() } -> same_as<bool>; + { _Mp::is_always_unique() } -> same_as<bool>; + bool_constant<_Mp::is_always_strided()>::value; + bool_constant<_Mp::is_always_exhaustive()>::value; + bool_constant<_Mp::is_always_unique()>::value; + }; + + template<typename _Mapping, typename... _Indices> + constexpr typename _Mapping::index_type + __linear_index_strides(const _Mapping& __m, _Indices... __indices) + noexcept + { + using _IndexType = typename _Mapping::index_type; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + auto __update = [&, __pos = 0u](_IndexType __idx) mutable + { + _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, + __m.extents().extent(__pos))); + __res += __idx * __m.stride(__pos++); + }; + (__update(__indices), ...); + } + return __res; + } + } + + template<typename _Extents> + class layout_stride::mapping + { + public: + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_stride; + + static_assert(__mdspan::__representable_size<extents_type, index_type>, + "The size of extents_type must be representable as index_type"); + + constexpr + mapping() noexcept + { + // The precondition is either statically asserted, or automatically + // satisfied because dynamic extents are zero-initialized. + size_t __stride = 1; + for (size_t __i = extents_type::rank(); __i > 0; --__i) + { + _M_strides[__i - 1] = index_type(__stride); + __stride *= size_t(_M_extents.extent(__i - 1)); + } + } + + constexpr + mapping(const mapping&) noexcept = default; + + template<typename _OIndexType> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + constexpr + mapping(const extents_type& __exts, + span<_OIndexType, extents_type::rank()> __strides) noexcept + : _M_extents(__exts) + { + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + _M_strides[__i] = index_type(as_const(__strides[__i])); + } + + template<typename _OIndexType> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + constexpr + mapping(const extents_type& __exts, + const array<_OIndexType, extents_type::rank()>& __strides) + noexcept + : mapping(__exts, + span<const _OIndexType, extents_type::rank()>(__strides)) + { } + + template<__mdspan::__mapping_alike _StridedMapping> + requires (is_constructible_v<extents_type, + typename _StridedMapping::extents_type> + && _StridedMapping::is_always_unique() + && _StridedMapping::is_always_strided()) + constexpr explicit(!( + is_convertible_v<typename _StridedMapping::extents_type, extents_type> + && __mdspan::__standardized_mapping<_StridedMapping>)) + mapping(const _StridedMapping& __other) noexcept + : _M_extents(__other.extents()) + { + using _OIndexType = _StridedMapping::index_type; + using _OExtents = _StridedMapping::extents_type; + + __glibcxx_assert(__mdspan::__offset(__other) == 0); + static_assert(__mdspan::__representable_size<_OExtents, index_type>, + "The size of StridedMapping::extents_type must be representable as" + " index_type"); + if constexpr (cmp_greater(__gnu_cxx::__int_traits<_OIndexType>::__max, + __gnu_cxx::__int_traits<index_type>::__max)) + __glibcxx_assert(!cmp_less( + __gnu_cxx::__int_traits<index_type>::__max, + __other.required_span_size()) + && "other.required_span_size() must be representable" + " as index_type"); + if constexpr (extents_type::rank() > 0) + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + _M_strides[__i] = index_type(__other.stride(__i)); + } + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_extents; } + + constexpr array<index_type, extents_type::rank()> + strides() const noexcept + { + array<index_type, extents_type::rank()> __ret; + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + __ret[__i] = _M_strides[__i]; + return __ret; + } + + constexpr index_type + required_span_size() const noexcept + { + if (__mdspan::__empty(_M_extents)) + return 0; + + index_type __ret = 1; + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + __ret += (_M_extents.extent(__i) - 1) * _M_strides[__i]; + return __ret; + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4314. Missing move in mdspan layout mapping::operator() + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == extents_type::rank()) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_strides(*this, + static_cast<index_type>(std::move(__indices))...); + } + + static constexpr bool + is_always_unique() noexcept { return true; } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4266. layout_stride::mapping should treat empty mappings as exhaustive + static constexpr bool + is_always_exhaustive() noexcept + { + return (_Extents::rank() == 0) || __mdspan::__contains_zero( + __mdspan::__static_extents<extents_type>()); + } + + static constexpr bool + is_always_strided() noexcept { return true; } + + static constexpr bool + is_unique() noexcept { return true; } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4266. layout_stride::mapping should treat empty mappings as exhaustive + constexpr bool + is_exhaustive() const noexcept + { + if constexpr (!is_always_exhaustive()) + { + auto __size = __mdspan::__size(_M_extents); + if(__size > 0) + return __size == required_span_size(); + } + return true; + } + + static constexpr bool + is_strided() noexcept { return true; } + + constexpr index_type + stride(rank_type __r) const noexcept { return _M_strides[__r]; } + + template<__mdspan::__mapping_alike _OMapping> + requires ((extents_type::rank() == _OMapping::extents_type::rank()) + && _OMapping::is_always_strided()) + friend constexpr bool + operator==(const mapping& __self, const _OMapping& __other) noexcept + { + if (__self.extents() != __other.extents()) + return false; + if constexpr (extents_type::rank() > 0) + for (size_t __i = 0; __i < extents_type::rank(); ++__i) + if (!cmp_equal(__self.stride(__i), __other.stride(__i))) + return false; + return __mdspan::__offset(__other) == 0; + } + + private: +#if __glibcxx_submdspan + template<typename... _Slices> + requires (extents_type::rank() == sizeof...(_Slices)) + friend constexpr auto + submdspan_mapping(const mapping& __mapping, _Slices... __slices) + { + if constexpr (sizeof...(_Slices) == 0) + return submdspan_mapping_result{__mapping, 0}; + else + { + auto __offset = __mdspan::__suboffset(__mapping, __slices...); + auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...); + auto __sub_strides + = __mdspan::__substrides<decltype(__sub_exts)>(__mapping, __slices...); + return submdspan_mapping_result{ + layout_stride::mapping(__sub_exts, __sub_strides), __offset}; + } + } +#endif + + using _Strides = typename __array_traits<index_type, + extents_type::rank()>::_Type; + [[no_unique_address]] extents_type _M_extents; + [[no_unique_address]] _Strides _M_strides; + }; + +#ifdef __glibcxx_padded_layouts + namespace __mdspan + { + constexpr size_t + __least_multiple(size_t __x, size_t __y) + { + if (__x <= 1) + return __y; + return (__y / __x + (__y % __x != 0)) * __x ; + } + + template<typename _IndexType> + constexpr bool + __is_representable_least_multiple(size_t __x, size_t __y) + { + constexpr auto __y_max = __gnu_cxx::__int_traits<_IndexType>::__max; + if(std::cmp_greater(__y, __y_max)) + return false; + + if(__x <= 1) + return true; + + auto __max_delta = __y_max - static_cast<_IndexType>(__y); + auto __y_mod_x = __y % __x; + auto __delta = (__y_mod_x == 0) ? size_t(0) : (__x - __y_mod_x); + return std::cmp_less_equal(__delta, __max_delta); + } + + template<typename _Extents, size_t _PaddingValue, typename _LayoutTraits, + size_t _Rank = _Extents::rank()> + concept __valid_static_stride = (_Extents::rank() <= 1) + || (_PaddingValue == dynamic_extent) + || (_Extents::static_extent(_LayoutTraits::_S_ext_idx) == dynamic_extent) + || (__is_representable_least_multiple<size_t>( + _PaddingValue, _Extents::static_extent(_LayoutTraits::_S_ext_idx))); + + template<size_t _PaddedStride, typename _Extents, + typename _LayoutTraits> + consteval bool + __is_representable_padded_size() + { + using _IndexType = typename _Extents::index_type; + auto __sta_exts = __static_extents<_Extents>( + _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end); + size_t __max = __gnu_cxx::__int_traits<_IndexType>::__max; + return __static_quotient(__sta_exts, __max / _PaddedStride) != 0; + } + + template<typename _Extents, size_t _PaddedStride, typename _LayoutTraits, + size_t _Rank = _Extents::rank()> + concept __valid_padded_size = (_Rank <= 1) + || (_PaddedStride == dynamic_extent) + || (!__all_static(__static_extents<_Extents>())) + || (__contains_zero(__static_extents<_Extents>())) + || (__is_representable_padded_size<_PaddedStride, _Extents, + _LayoutTraits>()); + + template<typename _Extents, typename _Stride, typename... _Indices> + constexpr typename _Extents::index_type + __linear_index_leftpad(const _Extents& __exts, _Stride __stride, + _Indices... __indices) + { + // i0 + stride*(i1 + extents.extent(1)*...) + using _IndexType = typename _Extents::index_type; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + _IndexType __mult = 1; + + auto __update_rest = [&, __pos = 1u](_IndexType __idx) mutable + { + __res += __idx * __mult; + __mult *= __exts.extent(__pos); + ++__pos; + }; + + auto __update = [&](_IndexType __idx, auto... __rest) + { + __res += __idx; + __mult = __stride.extent(0); + (__update_rest(__rest), ...); + }; + __update(__indices...); + } + return __res; + } + + template<typename _Extents, typename _Stride, typename... _Indices> + constexpr typename _Extents::index_type + __linear_index_rightpad(const _Extents& __exts, _Stride __stride, + _Indices... __indices) + { + // i[n-1] + stride*(i[n-2] + extents.extent(n-2])*...) + using _IndexType = typename _Extents::index_type; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + _IndexType __mult = 1; + array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...}; + + auto __update_rest = [&, __pos = __exts.rank()-1](_IndexType) mutable + { + --__pos; + __res += __ind_arr[__pos] * __mult; + __mult *= __exts.extent(__pos); + }; + + auto __update = [&](_IndexType, auto... __rest) + { + __res += __ind_arr[__exts.rank() - 1]; + __mult = __stride.extent(0); + (__update_rest(__rest), ...); + }; + __update(__indices...); + } + return __res; + } + + template<size_t _Rank> + struct _LeftPaddedLayoutTraits + { + using _LayoutSame = layout_left; + using _LayoutOther = layout_right; + + constexpr static const size_t _S_ext_idx = 0; + constexpr static const size_t _S_stride_idx = 1; + constexpr static const size_t _S_unpad_begin = 1; + constexpr static const size_t _S_unpad_end = _Rank; + + template<typename _IndexType, size_t _StaticStride, size_t..._Extents> + constexpr static auto + _S_make_padded_extent( + extents<_IndexType, _StaticStride> __stride, + const extents<_IndexType, _Extents...>& __exts) + { + auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>) + { + return extents<_IndexType, _StaticStride, + (_Extents...[_Is + 1])...>{ + __stride.extent(0), __exts.extent(_Is + 1)...}; + }; + return __impl(make_index_sequence<sizeof...(_Extents) - 1>()); + } + }; + + template<size_t _Rank> + struct _RightPaddedLayoutTraits + { + using _LayoutSame = layout_right; + using _LayoutOther = layout_left; + + constexpr static size_t _S_ext_idx = _Rank - 1; + constexpr static size_t _S_stride_idx = _Rank - 2; + constexpr static size_t _S_unpad_begin = 0; + constexpr static size_t _S_unpad_end = _Rank - 1; + + template<typename _IndexType, size_t _StaticStride, size_t..._Extents> + constexpr static auto + _S_make_padded_extent( + extents<_IndexType, _StaticStride> __stride, + const extents<_IndexType, _Extents...>& __exts) + { + auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>) + { + return extents<_IndexType, (_Extents...[_Is])..., _StaticStride>{ + __exts.extent(_Is)..., __stride.extent(0)}; + }; + return __impl(make_index_sequence<sizeof...(_Extents) - 1>()); + } + }; + + template<size_t _PaddingValue, typename _Extents, typename _LayoutTraits> + class _PaddedStorage + { + using _LayoutSame = typename _LayoutTraits::_LayoutSame; + + public: + using _IndexType = typename _Extents::index_type; + constexpr static size_t _S_rank = _Extents::rank(); + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4372. Weaken Mandates: for dynamic padding values in padded layouts + static_assert((_PaddingValue == dynamic_extent) + || (cmp_less_equal(_PaddingValue, + __gnu_cxx::__int_traits<_IndexType>::__max)), + "padding_value must be representable as index_type"); + + static_assert(__representable_size<_Extents, _IndexType>, + "The size of extents_type must be representable as index_type"); + + static_assert(__valid_static_stride<_Extents, _PaddingValue, + _LayoutTraits>, + "The padded stride must be representable as size_t"); + + static constexpr size_t _S_static_stride = [] consteval + { + constexpr size_t __rank = _Extents::rank(); + if constexpr (__rank <= 1) + return 0; + else + { + constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx; + constexpr size_t __sta_ext = _Extents::static_extent(__ext_idx); + if constexpr (__sta_ext == 0) + return size_t(0); + else if constexpr (_PaddingValue == dynamic_extent + || __sta_ext == dynamic_extent) + return dynamic_extent; + else + return __least_multiple(_PaddingValue, __sta_ext); + } + }(); + + static_assert(_S_static_stride == dynamic_extent + || cmp_less_equal(_S_static_stride, + __gnu_cxx::__int_traits<_IndexType>::__max), + "Padded stride must be representable as index_type"); + + static_assert(__valid_padded_size<_Extents, _S_static_stride, + _LayoutTraits>); + + constexpr + _PaddedStorage() noexcept + { + if constexpr (_S_rank > 1) + if constexpr (_S_static_stride == dynamic_extent + && _S_static_padextent() != dynamic_extent) + _M_stride = _Stride{_S_static_padextent()}; + } + + constexpr explicit + _PaddedStorage(const _Extents& __exts) + : _M_extents(__exts) + { + if constexpr (!__all_static(__static_extents<_Extents>())) + __glibcxx_assert(__is_representable_extents(_M_extents)); + + if constexpr (_S_rank > 1) + { + _IndexType __stride; + if constexpr (_PaddingValue == dynamic_extent) + __stride = _M_padextent(); + else if constexpr (_S_static_padextent() != dynamic_extent) + return; + else + { + __glibcxx_assert( + __is_representable_least_multiple<_IndexType>( + _PaddingValue, _M_padextent())); + + __stride = static_cast<_IndexType>( + __least_multiple(_PaddingValue, _M_padextent())); + + __glibcxx_assert(__is_representable_extents( + _LayoutTraits::_S_make_padded_extent( + std::dextents<_IndexType, 1>{__stride}, + _M_extents))); + } + _M_stride = _Stride{__stride}; + } + } + + constexpr explicit + _PaddedStorage(const _Extents& __exts, _IndexType __pad) + : _M_extents(__exts) + { + if constexpr (_PaddingValue != dynamic_extent) + __glibcxx_assert(cmp_equal(_PaddingValue, __pad)); + if constexpr (_S_rank > 1 && _S_static_stride == dynamic_extent) + { + __glibcxx_assert( + __is_representable_least_multiple<_IndexType>( + __pad, _M_padextent())); + + _M_stride = _Stride{static_cast<_IndexType>( + __least_multiple(__pad, _M_padextent()))}; + + __glibcxx_assert(__is_representable_extents( + _LayoutTraits::_S_make_padded_extent( + _M_stride, _M_extents))); + } + } + + template<typename _OExtents> + constexpr explicit + _PaddedStorage( + const typename _LayoutSame::template mapping<_OExtents>& __other) + : _PaddedStorage(_Extents(__other.extents())) + { + constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx; + constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx; + if constexpr (_S_rank > 1 && _PaddingValue != dynamic_extent) + { + static_assert(_S_static_stride == dynamic_extent + || _OExtents::static_extent(__ext_idx) == dynamic_extent + || _S_static_stride == _OExtents::static_extent(__ext_idx), + "The padded stride must be compatible with other"); + + if constexpr (_S_static_stride == dynamic_extent + || _OExtents::static_extent(__stride_idx) == dynamic_extent) + __glibcxx_assert(std::cmp_equal(_M_padstride(), + _M_padextent())); + } + } + + template<typename _OExtents> + constexpr explicit + _PaddedStorage(const typename layout_stride::mapping<_OExtents>& + __other) + : _M_extents(__other.extents()) + { + __glibcxx_assert(cmp_less_equal(__other.required_span_size(), + __gnu_cxx::__int_traits<_IndexType> + ::__max)); + + constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx; + if constexpr (_S_rank > 1) + { + if constexpr (_PaddingValue != dynamic_extent) + __glibcxx_assert(cmp_equal(__other.stride(__stride_idx), + _M_calc_padstride()) + && "The padded stride must be compatible with other"); + if constexpr (_S_static_stride == dynamic_extent) + _M_stride = _Stride{__other.stride(__stride_idx)}; + } + } + + template<typename _SamePaddedMapping> + constexpr explicit + _PaddedStorage(_LayoutTraits::_LayoutSame, + const _SamePaddedMapping& __other) + : _M_extents(__other.extents()) + { + if constexpr (_S_rank > 1) + { + static_assert(_PaddingValue == dynamic_extent + || _SamePaddedMapping::padding_value == dynamic_extent + || _PaddingValue == _SamePaddedMapping::padding_value, + "If neither PaddingValue is dynamic_extent, then they must " + "be equal"); + + constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx; + if constexpr (_PaddingValue != dynamic_extent) + __glibcxx_assert(cmp_equal(__other.stride(__stride_idx), + _M_calc_padstride()) + && "The padded stride must be compatible with other"); + if constexpr (_S_static_stride == dynamic_extent) + _M_stride = _Stride{__other.stride(__stride_idx)}; + } + __glibcxx_assert(cmp_less_equal(__other.required_span_size(), + __gnu_cxx::__int_traits<_IndexType>::__max)); + } + + template<typename _OtherPaddedMapping> + constexpr explicit + _PaddedStorage(_LayoutTraits::_LayoutOther, + const _OtherPaddedMapping& __other) noexcept + : _M_extents(__other.extents()) + { + __glibcxx_assert(cmp_less_equal(__other.required_span_size(), + __gnu_cxx::__int_traits<_IndexType>::__max)); + } + + static constexpr bool + _M_is_always_exhaustive() noexcept + { + if constexpr (_S_rank <= 1) + return true; + else + return _S_static_padextent() != dynamic_extent + && _S_static_stride != dynamic_extent + && _S_static_padextent() == _S_static_stride; + } + + constexpr bool + _M_is_exhaustive() const noexcept + { + if constexpr (_M_is_always_exhaustive()) + return true; + else + return cmp_equal(_M_padextent(), _M_padstride()); + } + + constexpr static size_t + _S_static_padextent() noexcept + { return _Extents::static_extent(_LayoutTraits::_S_ext_idx); } + + constexpr _IndexType + _M_padextent() const noexcept + { return _M_extents.extent(_LayoutTraits::_S_ext_idx); } + + constexpr _IndexType + _M_calc_padstride() const noexcept + { + if constexpr (_S_static_stride != dynamic_extent) + return _S_static_stride; + else if constexpr (_PaddingValue != dynamic_extent) + return __least_multiple(_PaddingValue, _M_padextent()); + else + return _M_padextent(); + } + + constexpr _IndexType + _M_padstride() const noexcept + { return _M_stride.extent(0); } + + constexpr _IndexType + _M_required_span_size() const noexcept + { + if constexpr (_S_rank == 0) + return 1; + else if (__mdspan::__empty(_M_extents)) + return 0; + else + { + size_t __stride = static_cast<size_t>(_M_padstride()); + size_t __prod_rest = __mdspan::__fwd_prod(_M_extents, + _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end); + size_t __delta = _M_padstride() - _M_padextent(); + return static_cast<_IndexType>(__stride * __prod_rest - __delta); + } + } + + template<typename _SamePaddedMapping> + constexpr bool + _M_equal(const _SamePaddedMapping& __other) const noexcept + { + return _M_extents == __other.extents() + && (_S_rank < 2 + || cmp_equal(_M_stride.extent(0), + __other.stride(_LayoutTraits::_S_stride_idx))); + } + + using _Stride = std::extents<_IndexType, _S_static_stride>; + [[no_unique_address]] _Stride _M_stride; + [[no_unique_address]] _Extents _M_extents; + }; + } + + template<size_t _PaddingValue> + template<typename _Extents> + class layout_left_padded<_PaddingValue>::mapping + { + public: + static constexpr size_t padding_value = _PaddingValue; + + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_left_padded<padding_value>; + + private: + static constexpr size_t _S_rank = extents_type::rank(); + using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue, + _Extents, __mdspan::_LeftPaddedLayoutTraits<_S_rank>>; + [[no_unique_address]] _PaddedStorage _M_storage; + + consteval friend size_t + __mdspan::__get_static_stride<mapping>(); + + constexpr index_type + _M_extent(size_t __r) const noexcept + { return _M_storage._M_extents.extent(__r); } + + constexpr index_type + _M_padstride() const noexcept + { return _M_storage._M_stride.extent(0); } + + public: + constexpr + mapping() noexcept + { } + + constexpr + mapping(const mapping&) noexcept = default; + + constexpr + mapping(const extents_type& __exts) + : _M_storage(__exts) + { } + + template<__mdspan::__valid_index_type<index_type> _OIndexType> + constexpr + mapping(const extents_type& __exts, _OIndexType __pad) + : _M_storage(__exts, + __mdspan::__index_type_cast<index_type>(std::move(__pad))) + { } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const layout_left::mapping<_OExtents>& __other) + : _M_storage(__other) + { } + + template<typename _OExtents> + requires is_constructible_v<_OExtents, extents_type> + constexpr explicit(!(_OExtents::rank() == 0 + && is_convertible_v<_OExtents, extents_type>)) + mapping(const typename layout_stride::mapping<_OExtents>& __other) + : _M_storage(__other) + { __glibcxx_assert(*this == __other); } + + template<typename _LeftPaddedMapping> + requires __mdspan::__is_left_padded_mapping<_LeftPaddedMapping> + && is_constructible_v<extents_type, + typename _LeftPaddedMapping::extents_type> + constexpr explicit( + !is_convertible_v<typename _LeftPaddedMapping::extents_type, + extents_type> + || _S_rank > 1 && (padding_value != dynamic_extent + || _LeftPaddedMapping::padding_value == dynamic_extent)) + mapping(const _LeftPaddedMapping& __other) + : _M_storage(layout_left{}, __other) + { } + + template<typename _RightPaddedMapping> + requires (__mdspan::__is_right_padded_mapping<_RightPaddedMapping> + || __mdspan::__mapping_of<layout_right, _RightPaddedMapping>) + && (_S_rank <= 1) + && is_constructible_v<extents_type, + typename _RightPaddedMapping::extents_type> + constexpr explicit(!is_convertible_v< + typename _RightPaddedMapping::extents_type, extents_type>) + mapping(const _RightPaddedMapping& __other) noexcept + : _M_storage(layout_right{}, __other) + { } + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_storage._M_extents; } + + constexpr array<index_type, _S_rank> + strides() const noexcept + { + array<index_type, _S_rank> __ret; + if constexpr (_S_rank > 0) + __ret[0] = 1; + if constexpr (_S_rank > 1) + __ret[1] = _M_padstride(); + if constexpr (_S_rank > 2) + for(size_t __i = 2; __i < _S_rank; ++__i) + __ret[__i] = __ret[__i - 1] * _M_extent(__i - 1); + return __ret; + } + + constexpr index_type + required_span_size() const noexcept + { return _M_storage._M_required_span_size(); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4314. Missing move in mdspan layout mapping::operator() + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == _S_rank) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_leftpad( + extents(), _M_storage._M_stride, + static_cast<index_type>(std::move(__indices))...); + } + + static constexpr bool + is_always_exhaustive() noexcept + { return _PaddedStorage::_M_is_always_exhaustive(); } + + constexpr bool + is_exhaustive() noexcept + { return _M_storage._M_is_exhaustive(); } + + static constexpr bool + is_always_unique() noexcept { return true; } + + static constexpr bool + is_unique() noexcept { return true; } + + static constexpr bool + is_always_strided() noexcept { return true; } + + static constexpr bool + is_strided() noexcept { return true; } + + constexpr index_type + stride(rank_type __r) const noexcept + { + __glibcxx_assert(__r < _S_rank); + if (__r == 0) + return 1; + else + return static_cast<index_type>( + static_cast<size_t>(_M_padstride()) * + static_cast<size_t>(__mdspan::__fwd_prod(extents(), 1, __r))); + } + + template<typename _LeftpadMapping> + requires(__mdspan::__is_left_padded_mapping<_LeftpadMapping> + && _LeftpadMapping::extents_type::rank() == _S_rank) + friend constexpr bool + operator==(const mapping& __self, const _LeftpadMapping& __other) + noexcept + { return __self._M_storage._M_equal(__other); } + + private: +#if __glibcxx_submdspan + template<typename... _Slices> + requires (extents_type::rank() == sizeof...(_Slices)) + friend constexpr auto + submdspan_mapping(const mapping& __mapping, _Slices... __slices) + { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } +#endif // __glibcxx_submdspan + }; + + template<size_t _PaddingValue> + template<typename _Extents> + class layout_right_padded<_PaddingValue>::mapping { + public: + static constexpr size_t padding_value = _PaddingValue; + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_right_padded<_PaddingValue>; + + private: + static constexpr size_t _S_rank = extents_type::rank(); + using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue, + _Extents, __mdspan::_RightPaddedLayoutTraits<_S_rank>>; + [[no_unique_address]] _PaddedStorage _M_storage; + + consteval friend size_t + __mdspan::__get_static_stride<mapping>(); + + constexpr index_type + _M_extent(size_t __r) const noexcept + { return _M_storage._M_extents.extent(__r); } + + constexpr index_type + _M_padstride() const noexcept + { return _M_storage._M_stride.extent(0); } + + public: + constexpr + mapping() noexcept + { } + + constexpr + mapping(const mapping&) noexcept = default; + + constexpr + mapping(const extents_type& __exts) + : _M_storage(__exts) + { } + + template<__mdspan::__valid_index_type<index_type> _OIndexType> + constexpr + mapping(const extents_type& __exts, _OIndexType __pad) + : _M_storage(__exts, + __mdspan::__index_type_cast<index_type>(std::move(__pad))) + { } + + template<typename _OExtents> + requires is_constructible_v<extents_type, _OExtents> + constexpr explicit(!is_convertible_v<_OExtents, extents_type>) + mapping(const layout_right::mapping<_OExtents>& __other) + : _M_storage(__other) + { } + + template<typename _OExtents> + requires is_constructible_v<_OExtents, extents_type> + constexpr explicit(!(_OExtents::rank() == 0 + && is_convertible_v<_OExtents, extents_type>)) + mapping(const typename layout_stride::mapping<_OExtents>& __other) + : _M_storage(__other) + { __glibcxx_assert(*this == __other); } + + template<typename _RightPaddedMapping> + requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping> + && is_constructible_v<extents_type, + typename _RightPaddedMapping::extents_type> + constexpr explicit( + !is_convertible_v<typename _RightPaddedMapping::extents_type, + extents_type> + || _S_rank > 1 && (padding_value != dynamic_extent + || _RightPaddedMapping::padding_value == dynamic_extent)) + mapping(const _RightPaddedMapping& __other) + : _M_storage(layout_right{}, __other) + { } + + template<typename _LeftPaddedMapping> + requires (__mdspan::__is_left_padded_mapping<_LeftPaddedMapping> + || __mdspan::__mapping_of<layout_left, _LeftPaddedMapping>) + && (_S_rank <= 1) + && is_constructible_v<extents_type, + typename _LeftPaddedMapping::extents_type> + constexpr explicit(!is_convertible_v< + typename _LeftPaddedMapping::extents_type, extents_type>) + mapping(const _LeftPaddedMapping& __other) noexcept + : _M_storage(layout_left{}, __other) + { } + + constexpr mapping& operator=(const mapping&) noexcept = default; + + constexpr const extents_type& + extents() const noexcept { return _M_storage._M_extents; } + + constexpr array<index_type, _S_rank> + strides() const noexcept + { + array<index_type, _S_rank> __ret; + if constexpr (_S_rank > 0) + __ret[_S_rank - 1] = 1; + if constexpr (_S_rank > 1) + __ret[_S_rank - 2] = _M_padstride(); + if constexpr (_S_rank > 2) + for(size_t __i = _S_rank - 2; __i > 0; --__i) + __ret[__i - 1] = __ret[__i] * _M_extent(__i); + return __ret; + } + + constexpr index_type + required_span_size() const noexcept + { return _M_storage._M_required_span_size(); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4314. Missing move in mdspan layout mapping::operator() + template<__mdspan::__valid_index_type<index_type>... _Indices> + requires (sizeof...(_Indices) == _S_rank) + constexpr index_type + operator()(_Indices... __indices) const noexcept + { + return __mdspan::__linear_index_rightpad( + extents(), _M_storage._M_stride, + static_cast<index_type>(std::move(__indices))...); + } + + static constexpr bool + is_always_exhaustive() noexcept + { return _PaddedStorage::_M_is_always_exhaustive(); } + + constexpr bool + is_exhaustive() noexcept + { return _M_storage._M_is_exhaustive(); } + + static constexpr bool + is_always_unique() noexcept { return true; } + + static constexpr bool + is_unique() noexcept { return true; } + + static constexpr bool + is_always_strided() noexcept { return true; } + + static constexpr bool + is_strided() noexcept { return true; } + + constexpr index_type + stride(rank_type __r) const noexcept + { + __glibcxx_assert(__r < _S_rank); + if constexpr (_S_rank <= 1) + return 1; + else if (__r == _S_rank - 1) + return 1; + else if (__r == _S_rank - 2) + return _M_padstride(); + else + return static_cast<index_type>( + static_cast<size_t>(_M_padstride()) * + static_cast<size_t>(__mdspan::__fwd_prod( + extents(), __r + 1, _S_rank - 1))); + } + + template<typename _RightPaddedMapping> + requires(__mdspan::__is_right_padded_mapping<_RightPaddedMapping> + && _RightPaddedMapping::extents_type::rank() == _S_rank) + friend constexpr bool + operator==(const mapping& __self, const _RightPaddedMapping& __other) + noexcept + { return __self._M_storage._M_equal(__other); } + +#if __glibcxx_submdspan + private: + template<typename... _Slices> + requires (extents_type::rank() == sizeof...(_Slices)) + friend constexpr auto + submdspan_mapping(const mapping& __mapping, _Slices... __slices) + { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } +#endif // __glibcxx_submdspan + }; +#endif // __glibcxx_padded_layouts + + template<typename _ElementType> + struct default_accessor + { + static_assert(!is_array_v<_ElementType>, + "ElementType must not be an array type"); + static_assert(!is_abstract_v<_ElementType>, + "ElementType must not be an abstract class type"); + + using offset_policy = default_accessor; + using element_type = _ElementType; + using reference = element_type&; + using data_handle_type = element_type*; + + constexpr + default_accessor() noexcept = default; + + template<typename _OElementType> + requires is_convertible_v<_OElementType(*)[], element_type(*)[]> + constexpr + default_accessor(default_accessor<_OElementType>) noexcept + { } + + constexpr reference + access(data_handle_type __p, size_t __i) const noexcept + { return __p[__i]; } + + constexpr data_handle_type + offset(data_handle_type __p, size_t __i) const noexcept + { return __p + __i; } + }; + +#ifdef __glibcxx_aligned_accessor + template<typename _ElementType, size_t _ByteAlignment> + struct aligned_accessor + { + static_assert(has_single_bit(_ByteAlignment), + "ByteAlignment must be a power of two"); + static_assert(_ByteAlignment >= alignof(_ElementType)); + + using offset_policy = default_accessor<_ElementType>; + using element_type = _ElementType; + using reference = element_type&; + using data_handle_type = element_type*; + + static constexpr size_t byte_alignment = _ByteAlignment; + + constexpr + aligned_accessor() noexcept = default; + + template<typename _OElementType, size_t _OByteAlignment> + requires (_OByteAlignment >= byte_alignment) + && is_convertible_v<_OElementType(*)[], element_type(*)[]> + constexpr + aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>) + noexcept + { } + + template<typename _OElementType> + requires is_convertible_v<_OElementType(*)[], element_type(*)[]> + constexpr explicit + aligned_accessor(default_accessor<_OElementType>) noexcept + { } + + template<typename _OElementType> + requires is_convertible_v<element_type(*)[], _OElementType(*)[]> + constexpr + operator default_accessor<_OElementType>() const noexcept + { return {}; } + + constexpr reference + access(data_handle_type __p, size_t __i) const noexcept + { return std::assume_aligned<byte_alignment>(__p)[__i]; } + + constexpr typename offset_policy::data_handle_type + offset(data_handle_type __p, size_t __i) const noexcept + { return std::assume_aligned<byte_alignment>(__p) + __i; } + }; +#endif + + namespace __mdspan + { + template<typename _Extents, typename _IndexType, size_t _Nm> + constexpr bool + __is_multi_index(const _Extents& __exts, span<_IndexType, _Nm> __indices) + { + static_assert(__exts.rank() == _Nm); + for (size_t __i = 0; __i < __exts.rank(); ++__i) + if (__indices[__i] >= __exts.extent(__i)) + return false; + return true; + } + } + + template<typename _ElementType, typename _Extents, + typename _LayoutPolicy = layout_right, + typename _AccessorPolicy = default_accessor<_ElementType>> + class mdspan + { + static_assert(!is_array_v<_ElementType>, + "ElementType must not be an array type"); + static_assert(!is_abstract_v<_ElementType>, + "ElementType must not be an abstract class type"); + static_assert(__mdspan::__is_extents<_Extents>, + "Extents must be a specialization of std::extents"); + static_assert(is_same_v<_ElementType, + typename _AccessorPolicy::element_type>); + + public: + using extents_type = _Extents; + using layout_type = _LayoutPolicy; + using accessor_type = _AccessorPolicy; + using mapping_type = typename layout_type::template mapping<extents_type>; + using element_type = _ElementType; + using value_type = remove_cv_t<element_type>; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using data_handle_type = typename accessor_type::data_handle_type; + using reference = typename accessor_type::reference; + + static constexpr rank_type + rank() noexcept { return extents_type::rank(); } + + static constexpr rank_type + rank_dynamic() noexcept { return extents_type::rank_dynamic(); } + + static constexpr size_t + static_extent(rank_type __r) noexcept + { return extents_type::static_extent(__r); } + + constexpr index_type + extent(rank_type __r) const noexcept { return extents().extent(__r); } + + constexpr + mdspan() + requires (rank_dynamic() > 0) + && is_default_constructible_v<data_handle_type> + && is_default_constructible_v<mapping_type> + && is_default_constructible_v<accessor_type> = default; + + constexpr + mdspan(const mdspan& __other) = default; + + constexpr + mdspan(mdspan&& __other) = default; + + template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> + requires (sizeof...(_OIndexTypes) == rank() + || sizeof...(_OIndexTypes) == rank_dynamic()) + && is_constructible_v<mapping_type, extents_type> + && is_default_constructible_v<accessor_type> + constexpr explicit + mdspan(data_handle_type __handle, _OIndexTypes... __exts) + : _M_accessor(), + _M_mapping(_Extents(static_cast<index_type>(std::move(__exts))...)), + _M_handle(std::move(__handle)) + { } + + template<typename _OIndexType, size_t _Nm> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + && (_Nm == rank() || _Nm == rank_dynamic()) + && is_constructible_v<mapping_type, extents_type> + && is_default_constructible_v<accessor_type> + constexpr explicit(_Nm != rank_dynamic()) + mdspan(data_handle_type __handle, span<_OIndexType, _Nm> __exts) + : _M_accessor(), _M_mapping(extents_type(__exts)), + _M_handle(std::move(__handle)) + { } + + template<typename _OIndexType, size_t _Nm> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + && (_Nm == rank() || _Nm == rank_dynamic()) + && is_constructible_v<mapping_type, extents_type> + && is_default_constructible_v<accessor_type> + constexpr explicit(_Nm != rank_dynamic()) + mdspan(data_handle_type __handle, const array<_OIndexType, _Nm>& __exts) + : _M_accessor(), _M_mapping(extents_type(__exts)), + _M_handle(std::move(__handle)) + { } + + constexpr + mdspan(data_handle_type __handle, const extents_type& __exts) + requires is_constructible_v<mapping_type, const extents_type&> + && is_default_constructible_v<accessor_type> + : _M_accessor(), _M_mapping(__exts), _M_handle(std::move(__handle)) + { } + + constexpr + mdspan(data_handle_type __handle, const mapping_type& __mapping) + requires is_default_constructible_v<accessor_type> + : _M_accessor(), _M_mapping(__mapping), _M_handle(std::move(__handle)) + { } + + constexpr + mdspan(data_handle_type __handle, const mapping_type& __mapping, + const accessor_type& __accessor) + : _M_accessor(__accessor), _M_mapping(__mapping), + _M_handle(std::move(__handle)) + { } + + template<typename _OElementType, typename _OExtents, typename _OLayout, + typename _OAccessor> + requires is_constructible_v<mapping_type, + const typename _OLayout::template mapping<_OExtents>&> + && is_constructible_v<accessor_type, const _OAccessor&> + constexpr explicit(!is_convertible_v< + const typename _OLayout::template mapping<_OExtents>&, mapping_type> + || !is_convertible_v<const _OAccessor&, accessor_type>) + mdspan(const mdspan<_OElementType, _OExtents, _OLayout, _OAccessor>& + __other) + : _M_accessor(__other.accessor()), _M_mapping(__other.mapping()), + _M_handle(__other.data_handle()) + { + static_assert(is_constructible_v<data_handle_type, + const typename _OAccessor::data_handle_type&>); + static_assert(is_constructible_v<extents_type, _OExtents>); + } + + constexpr mdspan& + operator=(const mdspan& __other) = default; + + constexpr mdspan& + operator=(mdspan&& __other) = default; + + template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> + requires (sizeof...(_OIndexTypes) == rank()) + constexpr reference + operator[](_OIndexTypes... __indices) const + { + auto __checked_call = [this](auto... __idxs) -> index_type + { + if constexpr (sizeof...(__idxs) > 0) + __glibcxx_assert(__mdspan::__is_multi_index(extents(), + span<const index_type, sizeof...(__idxs)>({__idxs...}))); + return _M_mapping(__idxs...); + }; + + auto __index = __checked_call( + static_cast<index_type>(std::move(__indices))...); + return _M_accessor.access(_M_handle, __index); + } + + template<typename _OIndexType> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + constexpr reference + operator[](span<_OIndexType, rank()> __indices) const + { + auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>) + -> reference + { return (*this)[index_type(as_const(__indices[_Counts]))...]; }; + return __call(make_index_sequence<rank()>()); + } + + template<typename _OIndexType> + requires __mdspan::__valid_index_type<const _OIndexType&, index_type> + constexpr reference + operator[](const array<_OIndexType, rank()>& __indices) const + { return (*this)[span<const _OIndexType, rank()>(__indices)]; } + + constexpr size_type + size() const noexcept + { + __glibcxx_assert(cmp_less_equal(_M_mapping.required_span_size(), + __gnu_cxx::__int_traits<size_t> + ::__max)); + return size_type(__mdspan::__size(extents())); + } + + [[nodiscard]] + constexpr bool + empty() const noexcept + { return __mdspan::__empty(extents()); } + + friend constexpr void + swap(mdspan& __x, mdspan& __y) noexcept + { + using std::swap; + swap(__x._M_mapping, __y._M_mapping); + swap(__x._M_accessor, __y._M_accessor); + swap(__x._M_handle, __y._M_handle); + } + + constexpr const extents_type& + extents() const noexcept { return _M_mapping.extents(); } + + constexpr const data_handle_type& + data_handle() const noexcept { return _M_handle; } + + constexpr const mapping_type& + mapping() const noexcept { return _M_mapping; } + + constexpr const accessor_type& + accessor() const noexcept { return _M_accessor; } + + // Strengthened noexcept for all `is_*` methods. + + static constexpr bool + is_always_unique() noexcept(noexcept(mapping_type::is_always_unique())) + { return mapping_type::is_always_unique(); } + + static constexpr bool + is_always_exhaustive() + noexcept(noexcept(mapping_type::is_always_exhaustive())) + { return mapping_type::is_always_exhaustive(); } + + static constexpr bool + is_always_strided() + noexcept(noexcept(mapping_type::is_always_strided())) + { return mapping_type::is_always_strided(); } + + constexpr bool + is_unique() const noexcept(noexcept(_M_mapping.is_unique())) + { return _M_mapping.is_unique(); } + + constexpr bool + is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive())) + { return _M_mapping.is_exhaustive(); } + + constexpr bool + is_strided() const noexcept(noexcept(_M_mapping.is_strided())) + { return _M_mapping.is_strided(); } + + constexpr index_type + stride(rank_type __r) const { return _M_mapping.stride(__r); } + + private: + [[no_unique_address]] accessor_type _M_accessor = accessor_type(); + [[no_unique_address]] mapping_type _M_mapping = mapping_type(); + [[no_unique_address]] data_handle_type _M_handle = data_handle_type(); + }; + + template<typename _CArray> + requires is_array_v<_CArray> && (rank_v<_CArray> == 1) + mdspan(_CArray&) + -> mdspan<remove_all_extents_t<_CArray>, + extents<size_t, extent_v<_CArray, 0>>>; + + template<typename _Pointer> + requires is_pointer_v<remove_reference_t<_Pointer>> + mdspan(_Pointer&&) + -> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>; + + template<typename _ElementType, typename... _Integrals> + requires (is_convertible_v<_Integrals, size_t> && ...) + && (sizeof...(_Integrals) > 0) + explicit mdspan(_ElementType*, _Integrals...) + -> mdspan<_ElementType, + extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>; + + template<typename _ElementType, typename _OIndexType, size_t _Nm> + mdspan(_ElementType*, span<_OIndexType, _Nm>) + -> mdspan<_ElementType, dextents<size_t, _Nm>>; + + template<typename _ElementType, typename _OIndexType, size_t _Nm> + mdspan(_ElementType*, const array<_OIndexType, _Nm>&) + -> mdspan<_ElementType, dextents<size_t, _Nm>>; + + template<typename _ElementType, typename _IndexType, size_t... _ExtentsPack> + mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&) + -> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>; + + template<typename _ElementType, typename _MappingType> + mdspan(_ElementType*, const _MappingType&) + -> mdspan<_ElementType, typename _MappingType::extents_type, + typename _MappingType::layout_type>; + + template<typename _MappingType, typename _AccessorType> + mdspan(const typename _AccessorType::data_handle_type&, const _MappingType&, + const _AccessorType&) + -> mdspan<typename _AccessorType::element_type, + typename _MappingType::extents_type, + typename _MappingType::layout_type, _AccessorType>; + +#if __glibcxx_submdspan + namespace __mdspan + { + template<typename _IndexType, typename _Slice> + constexpr auto + __canonical_index(_Slice&& __slice) + { + if constexpr (__detail::__integral_constant_like<_Slice>) + { + static_assert(__is_representable_integer<_IndexType>(_Slice::value)); + static_assert(_Slice::value >= 0); + return std::cw<_IndexType(_Slice::value)>; + } + else + return __mdspan::__index_type_cast<_IndexType>(std::move(__slice)); + } + + template<typename _IndexType, typename _Slice> + constexpr auto + __slice_cast(_Slice&& __slice) + { + using _SliceType = remove_cvref_t<_Slice>; + if constexpr (is_convertible_v<_SliceType, full_extent_t>) + return static_cast<full_extent_t>(std::move(__slice)); + else if constexpr (is_convertible_v<_SliceType, _IndexType>) + return __mdspan::__canonical_index<_IndexType>(std::move(__slice)); + else if constexpr (__is_strided_slice<_SliceType>) + { + auto __extent + = __mdspan::__canonical_index<_IndexType>(std::move(__slice.extent)); + auto __offset + = __mdspan::__canonical_index<_IndexType>(std::move(__slice.offset)); + if constexpr (is_same_v<decltype(__extent), + constant_wrapper<_IndexType(0)>>) + return strided_slice{ + .offset = __offset, + .extent = __extent, + .stride = cw<_IndexType(1)> + }; + else + return strided_slice{ + .offset = __offset, + .extent = __extent, + .stride + = __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride)) + }; + } + else + { + auto [__sbegin, __send] = std::move(__slice); + auto __offset + = __mdspan::__canonical_index<_IndexType>(std::move(__sbegin)); + auto __end + = __mdspan::__canonical_index<_IndexType>(std::move(__send)); + return strided_slice{ + .offset = __offset, + .extent = __mdspan::__canonical_index<_IndexType>(__end - __offset), + .stride = cw<_IndexType(1)> + }; + } + } + + template<typename _IndexType, size_t _Extent, typename _OIndexType> + constexpr void + __check_valid_index(const extents<_IndexType, _Extent>& __ext, + const _OIndexType& __idx) + { + if constexpr (__is_constant_wrapper<_OIndexType> + && _Extent != dynamic_extent) + { + static_assert(_OIndexType::value >= 0); + static_assert(std::cmp_less_equal(_OIndexType::value, _Extent)); + } + else + __glibcxx_assert(__idx <= __ext.extent(0)); +} + + template<typename _IndexType, size_t _Extent, typename _Slice> + constexpr void + __check_valid_slice(const extents<_IndexType, _Extent>& __ext, + const _Slice& __slice) + { + if constexpr (__is_strided_slice<_Slice>) + { + // DEVIATION: For empty slices, P3663r3 does not allow us to check + // that this is less than or equal to the k-th extent (at runtime). + // We're only allowed to check if __slice.offset, __slice.extent + // are constant wrappers and __ext is a static extent. + __mdspan::__check_valid_index(__ext, __slice.offset); + __mdspan::__check_valid_index(__ext, __slice.extent); + + if constexpr (__is_constant_wrapper<typename _Slice::extent_type> + && __is_constant_wrapper<typename _Slice::stride_type>) + static_assert(_Slice::stride_type::value > 0); + else + __glibcxx_assert(__slice.extent == 0 || __slice.stride > 0); + + if constexpr (__is_constant_wrapper<typename _Slice::offset_type> + && __is_constant_wrapper<typename _Slice::extent_type> + && _Extent != dynamic_extent) + static_assert(std::cmp_greater_equal( + _Extent - _Slice::offset_type::value, + _Slice::extent_type::value)); + else + __glibcxx_assert(__ext.extent(0) - __slice.offset + >= __slice.extent); + } + else if constexpr (__is_constant_wrapper<_Slice> + && _Extent != dynamic_extent) + static_assert(std::cmp_less(_Slice::value, _Extent)); + else if constexpr (convertible_to<_Slice, _IndexType>) + __glibcxx_assert(__slice < __ext.extent(0)); + } + + template<typename _Extents, typename... _Slices> + constexpr void + __check_valid_slices(const _Extents& __exts, const _Slices&... __slices) + { + constexpr auto __rank = _Extents::rank(); + auto __impl = [&]<size_t... _Is>(index_sequence<_Is...>) + { + ((__mdspan::__check_valid_slice(__extract_extent<_Is>(__exts), + __slices...[_Is])),...); + }; + __impl(make_index_sequence<__rank>()); + } + + template<typename _Slice> + using __full_extent_t = std::full_extent_t; + + // Enables ADL-only calls from submdspan. + void submdspan_mapping() = delete; + + template<typename _Mapping, typename... _Slices> + concept __sliceable_mapping = requires(const _Mapping __m, _Slices... __slices) + { + { submdspan_mapping(__m, __slices...) } -> __submdspan_mapping_result; + }; + + template<typename _Mapping, typename... _Slices> + constexpr auto + __submapping(const _Mapping& __mapping, _Slices... __slices) + { + __mdspan::__check_valid_slices(__mapping.extents(), __slices...); + return submdspan_mapping(__mapping, __slices...); + } + } + + template<typename _IndexType, size_t... _Extents, typename... _RawSlices> + requires (sizeof...(_RawSlices) == sizeof...(_Extents)) + constexpr auto + submdspan_extents(const extents<_IndexType, _Extents...>& __exts, + _RawSlices... __raw_slices) + { + auto __impl = [&__exts](auto... __slices) + { + __mdspan::__check_valid_slices(__exts, __slices...); + return __mdspan::__subextents(__exts, __slices...); + }; + return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...); + } + + template<typename _IndexType, size_t... _Extents, typename... _RawSlices> + requires (sizeof...(_Extents) == sizeof...(_RawSlices)) + constexpr auto + submdspan_canonicalize_slices(const extents<_IndexType, _Extents...>& __exts, + _RawSlices... __raw_slices) + { + auto __impl = [&__exts](auto... __slices) + { + __mdspan::__check_valid_slices(__exts, __slices...); + return std::make_tuple(__slices...); + }; + return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...); + } + + template<typename _ElementType, typename _Extents, typename _Layout, + typename _Accessor, typename... _RawSlices> + requires (sizeof...(_RawSlices) == _Extents::rank() + && __mdspan::__sliceable_mapping<typename _Layout::mapping<_Extents>, + __mdspan::__full_extent_t<_RawSlices>...>) + constexpr auto + submdspan( + const mdspan<_ElementType, _Extents, _Layout, _Accessor>& __md, + _RawSlices... __raw_slices) + { + using _IndexType = typename _Extents::index_type; + auto [__mapping, __offset] = __mdspan::__submapping( + __md.mapping(), __mdspan::__slice_cast<_IndexType>(__raw_slices)...); + return std::mdspan( + __md.accessor().offset(__md.data_handle(), __offset), + std::move(__mapping), + typename _Accessor::offset_policy(__md.accessor())); + } +#endif // __glibcxx_submdspan + +_GLIBCXX_END_NAMESPACE_VERSION +} +#endif +#endif diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory index 99f542d..9763760 100644 --- a/libstdc++-v3/include/std/memory +++ b/libstdc++-v3/include/std/memory @@ -97,6 +97,11 @@ # include <bits/out_ptr.h> #endif +#if __cplusplus > 202302L +# include <bits/indirect.h> +#endif + +#define __glibcxx_want_addressof_constexpr #define __glibcxx_want_allocator_traits_is_always_equal #define __glibcxx_want_assume_aligned #define __glibcxx_want_atomic_shared_ptr @@ -104,16 +109,21 @@ #define __glibcxx_want_constexpr_dynamic_alloc #define __glibcxx_want_constexpr_memory #define __glibcxx_want_enable_shared_from_this +#define __glibcxx_want_indirect +#define __glibcxx_want_is_sufficiently_aligned #define __glibcxx_want_make_unique #define __glibcxx_want_out_ptr #define __glibcxx_want_parallel_algorithm +#define __glibcxx_want_polymorphic #define __glibcxx_want_ranges #define __glibcxx_want_raw_memory_algorithms #define __glibcxx_want_shared_ptr_arrays #define __glibcxx_want_shared_ptr_weak_type #define __glibcxx_want_smart_ptr_for_overwrite +#define __glibcxx_want_start_lifetime_as #define __glibcxx_want_to_address #define __glibcxx_want_transparent_operators +#define __glibcxx_want_smart_ptr_owner_equality #include <bits/version.h> #if __cplusplus >= 201103L && __cplusplus <= 202002L && _GLIBCXX_HOSTED diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex index b3f89c0..d4fc4c6 100644 --- a/libstdc++-v3/include/std/mutex +++ b/libstdc++-v3/include/std/mutex @@ -179,31 +179,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_try_lock_until(const chrono::time_point<chrono::system_clock, _Duration>& __atime) { - auto __s = chrono::time_point_cast<chrono::seconds>(__atime); - auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); - - __gthread_time_t __ts = { - static_cast<std::time_t>(__s.time_since_epoch().count()), - static_cast<long>(__ns.count()) - }; - + __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime); return static_cast<_Derived*>(this)->_M_timedlock(__ts); } -#ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK +#if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK template<typename _Duration> bool _M_try_lock_until(const chrono::time_point<chrono::steady_clock, _Duration>& __atime) { - auto __s = chrono::time_point_cast<chrono::seconds>(__atime); - auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); - - __gthread_time_t __ts = { - static_cast<std::time_t>(__s.time_since_epoch().count()), - static_cast<long>(__ns.count()) - }; - + __gthread_time_t __ts = chrono::__to_timeout_gthread_time_t(__atime); return static_cast<_Derived*>(this)->_M_clocklock(CLOCK_MONOTONIC, __ts); } @@ -377,7 +363,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_timedlock(const __gthread_time_t& __ts) { return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts); } -#ifdef _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK +#if _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK bool _M_clocklock(clockid_t __clockid, const __gthread_time_t& __ts) { return !pthread_mutex_clocklock(&_M_mutex, __clockid, &__ts); } @@ -733,7 +719,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } -#ifdef __cpp_lib_scoped_lock // C++ >= 17 && hosted && gthread +#ifdef __cpp_lib_scoped_lock // C++ >= 17 /** @brief A scoped lock type for multiple lockable objects. * * A scoped_lock controls mutex ownership within a scope, releasing diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric index 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..8b9fa92 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -36,6 +36,7 @@ #define __glibcxx_want_freestanding_optional #define __glibcxx_want_optional +#define __glibcxx_want_optional_range_support #define __glibcxx_want_constrained_equality #include <bits/version.h> @@ -57,6 +58,11 @@ #if __cplusplus > 202002L # include <concepts> #endif +#ifdef __cpp_lib_optional_range_support // C++ >= 26 +# include <bits/formatfwd.h> +# include <bits/ranges_base.h> +# include <bits/stl_iterator.h> +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -771,6 +777,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION # define _GLIBCXX_USE_CONSTRAINTS_FOR_OPTIONAL 1 #endif + template<typename _Tp> + inline constexpr bool __is_valid_contained_type_for_optional = + ( +#if __cpp_lib_optional >= 202506L + is_lvalue_reference_v<_Tp> || +#endif + (is_object_v<_Tp> && is_destructible_v<_Tp> && !is_array_v<_Tp>) + ) + && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, nullopt_t> + && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, in_place_t>; + /** * @brief Class template for optional values. */ @@ -789,9 +806,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Unique tag type. optional<_Tp>> { - static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>); - static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>); - static_assert(is_object_v<_Tp> && !is_array_v<_Tp>); + static_assert(__is_valid_contained_type_for_optional<_Tp>); private: using _Base = _Optional_base<_Tp>; @@ -858,6 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: using value_type = _Tp; +#ifdef __cpp_lib_optional_range_support // >= C++26 + using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional>; + using const_iterator = __gnu_cxx::__normal_iterator<const _Tp*, optional>; +#endif constexpr optional() noexcept { } @@ -884,7 +903,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(is_nothrow_constructible_v<_Tp, const _Up&>) { if (__t) - emplace(__t._M_get()); + emplace(__t._M_fwd()); } template<typename _Up> @@ -896,7 +915,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(is_nothrow_constructible_v<_Tp, _Up>) { if (__t) - emplace(std::move(__t._M_get())); + emplace(std::move(__t)._M_fwd()); } template<typename... _Args> @@ -946,7 +965,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(is_nothrow_constructible_v<_Tp, const _Up&>) { if (__t) - emplace(__t._M_get()); + emplace(__t._M_fwd()); } template<typename _Up, @@ -959,7 +978,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(is_nothrow_constructible_v<_Tp, const _Up&>) { if (__t) - emplace(__t._M_get()); + emplace(__t._M_fwd()); } template<typename _Up, @@ -972,7 +991,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(is_nothrow_constructible_v<_Tp, _Up>) { if (__t) - emplace(std::move(__t._M_get())); + emplace(std::move(__t)._M_fwd()); } template<typename _Up, @@ -985,7 +1004,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(is_nothrow_constructible_v<_Tp, _Up>) { if (__t) - emplace(std::move(__t._M_get())); + emplace(std::move(__t)._M_fwd()); } template<typename... _Args, @@ -1064,9 +1083,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__u) { if (this->_M_is_engaged()) - this->_M_get() = __u._M_get(); + this->_M_get() = __u._M_fwd(); else - this->_M_construct(__u._M_get()); + this->_M_construct(__u._M_fwd()); } else { @@ -1098,9 +1117,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__u) { if (this->_M_is_engaged()) - this->_M_get() = std::move(__u._M_get()); + this->_M_get() = std::move(__u)._M_fwd(); else - this->_M_construct(std::move(__u._M_get())); + this->_M_construct(std::move(__u)._M_fwd()); } else { @@ -1158,6 +1177,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } +#ifdef __cpp_lib_optional_range_support // >= C++26 + // Iterator support. + constexpr iterator begin() noexcept + { + return iterator( + this->_M_is_engaged() ? std::addressof(this->_M_get()) : nullptr + ); + } + + constexpr const_iterator begin() const noexcept + { + return const_iterator( + this->_M_is_engaged() ? std::addressof(this->_M_get()) : nullptr + ); + } + + constexpr iterator end() noexcept + { + return begin() + has_value(); + } + + constexpr const_iterator end() const noexcept + { + return begin() + has_value(); + } +#endif // __cpp_lib_optional_range_support + // Observers. constexpr const _Tp* operator->() const noexcept @@ -1239,30 +1285,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __throw_bad_optional_access(); } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4406. value_or return statement is inconsistent with Mandates template<typename _Up = remove_cv_t<_Tp>> - constexpr _Tp + constexpr remove_cv_t<_Tp> value_or(_Up&& __u) const& { - static_assert(is_copy_constructible_v<_Tp>); - static_assert(is_convertible_v<_Up&&, _Tp>); + using _Xp = remove_cv_t<_Tp>; + static_assert(is_convertible_v<const _Tp&, _Xp>); + static_assert(is_convertible_v<_Up, _Xp>); if (this->_M_is_engaged()) return this->_M_get(); - else - return static_cast<_Tp>(std::forward<_Up>(__u)); + return std::forward<_Up>(__u); } template<typename _Up = remove_cv_t<_Tp>> - constexpr _Tp + constexpr remove_cv_t<_Tp> value_or(_Up&& __u) && { - static_assert(is_move_constructible_v<_Tp>); - static_assert(is_convertible_v<_Up&&, _Tp>); + using _Xp = remove_cv_t<_Tp>; + static_assert(is_convertible_v<_Tp, _Xp>); + static_assert(is_convertible_v<_Up, _Xp>); if (this->_M_is_engaged()) return std::move(this->_M_get()); - else - return static_cast<_Tp>(std::forward<_Up>(__u)); + return std::forward<_Up>(__u); } #if __cpp_lib_optional >= 202110L // C++23 @@ -1273,7 +1321,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION and_then(_Fn&& __f) & { using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp&>>; - static_assert(__is_optional_v<remove_cvref_t<_Up>>, + static_assert(__is_optional_v<_Up>, "the function passed to std::optional<T>::and_then " "must return a std::optional"); if (has_value()) @@ -1301,7 +1349,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION and_then(_Fn&& __f) && { using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp>>; - static_assert(__is_optional_v<remove_cvref_t<_Up>>, + static_assert(__is_optional_v<_Up>, "the function passed to std::optional<T>::and_then " "must return a std::optional"); if (has_value()) @@ -1315,7 +1363,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION and_then(_Fn&& __f) const && { using _Up = remove_cvref_t<invoke_result_t<_Fn, const _Tp>>; - static_assert(__is_optional_v<remove_cvref_t<_Up>>, + static_assert(__is_optional_v<_Up>, "the function passed to std::optional<T>::and_then " "must return a std::optional"); if (has_value()) @@ -1404,6 +1452,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: using _Base::_M_get; + [[__gnu__::__always_inline__]] + constexpr _Tp& + _M_fwd() & noexcept + { return _M_get(); } + + [[__gnu__::__always_inline__]] + constexpr _Tp&& + _M_fwd() && noexcept + { return std::move(_M_get()); } + + [[__gnu__::__always_inline__]] + constexpr const _Tp& + _M_fwd() const& noexcept + { return _M_get(); } + + [[__gnu__::__always_inline__]] + constexpr const _Tp&& + _M_fwd() const&& noexcept + { return std::move(_M_get()); } + template<typename _Up> friend class optional; #if __cpp_lib_optional >= 202110L // C++23 @@ -1416,6 +1484,337 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif }; +#if __cpp_lib_optional >= 202506L // C++26 + template<typename _Tp> + class optional<_Tp&>; + + template<typename _Tp> + constexpr bool __is_optional_ref_v = false; + + template<typename _Tp> + constexpr bool __is_optional_ref_v<optional<_Tp&>> = true; + + template<typename _Tp> + struct __optional_ref_base + {}; + +#ifdef __cpp_lib_optional_range_support // >= C++26 + template<typename _Tp> + struct __optional_ref_base<_Tp[]> + {}; + + template<typename _Tp> + requires is_object_v<_Tp> + struct __optional_ref_base<_Tp> + { + using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional<_Tp&>>; + }; +#endif // __cpp_lib_optional_range_support + + template<typename _Tp> + class optional<_Tp&> : public __optional_ref_base<_Tp> + { + static_assert(__is_valid_contained_type_for_optional<_Tp&>); + + public: + using value_type = _Tp; + + // Constructors. + constexpr optional() noexcept = default; + constexpr optional(nullopt_t) noexcept : optional() {} + constexpr optional(const optional&) noexcept = default; + + template<typename _Arg> + requires is_constructible_v<_Tp&, _Arg> + && (!reference_constructs_from_temporary_v<_Tp&, _Arg>) + explicit constexpr + optional(in_place_t, _Arg&& __arg) + { + __convert_ref_init_val(std::forward<_Arg>(__arg)); + } + + template<typename _Up> + requires (!is_same_v<remove_cvref_t<_Up>, optional>) + && (!is_same_v<remove_cvref_t<_Up>, in_place_t>) + && is_constructible_v<_Tp&, _Up> + && (!reference_constructs_from_temporary_v<_Tp&, _Up>) + explicit(!is_convertible_v<_Up, _Tp&>) + constexpr + optional(_Up&& __u) + noexcept(is_nothrow_constructible_v<_Tp&, _Up>) + { + __convert_ref_init_val(std::forward<_Up>(__u)); + } + + template<typename _Up> + requires (!is_same_v<remove_cvref_t<_Up>, optional>) + && (!is_same_v<remove_cvref_t<_Up>, in_place_t>) + && is_constructible_v<_Tp&, _Up> + && reference_constructs_from_temporary_v<_Tp&, _Up> + explicit(!is_convertible_v<_Up, _Tp&>) + constexpr + optional(_Up&& __u) = delete; + + // optional<U> & + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, _Up&> + && (!reference_constructs_from_temporary_v<_Tp&, _Up&>) + explicit(!is_convertible_v<_Up&, _Tp&>) + constexpr + optional(optional<_Up>& __rhs) + noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) + { + if (__rhs) + __convert_ref_init_val(__rhs._M_fwd()); + } + + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, _Up&> + && reference_constructs_from_temporary_v<_Tp&, _Up&> + explicit(!is_convertible_v<_Up&, _Tp&>) + constexpr + optional(optional<_Up>& __rhs) = delete; + + // const optional<U>& + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, const _Up&> + && (!reference_constructs_from_temporary_v<_Tp&, const _Up&>) + explicit(!is_convertible_v<const _Up&, _Tp&>) + constexpr + optional(const optional<_Up>& __rhs) + noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) + { + if (__rhs) + __convert_ref_init_val(__rhs._M_fwd()); + } + + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, const _Up&> + && reference_constructs_from_temporary_v<_Tp&, const _Up&> + explicit(!is_convertible_v<const _Up&, _Tp&>) + constexpr + optional(const optional<_Up>& __rhs) = delete; + + // optional<U>&& + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, _Up> + && (!reference_constructs_from_temporary_v<_Tp&, _Up>) + explicit(!is_convertible_v<_Up, _Tp&>) + constexpr + optional(optional<_Up>&& __rhs) + noexcept(is_nothrow_constructible_v<_Tp&, _Up>) + { + if (__rhs) + __convert_ref_init_val(std::move(__rhs)._M_fwd()); + } + + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, _Up> + && reference_constructs_from_temporary_v<_Tp&, _Up> + explicit(!is_convertible_v<_Up, _Tp&>) + constexpr + optional(optional<_Up>&& __rhs) = delete; + + // const optional<U>&& + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, const _Up> + && (!reference_constructs_from_temporary_v<_Tp&, _Up>) + explicit(!is_convertible_v<const _Up, _Tp&>) + constexpr + optional(const optional<_Up>&& __rhs) + noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) + { + if (__rhs) + __convert_ref_init_val(std::move(__rhs)._M_fwd()); + } + + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, const _Up> + && reference_constructs_from_temporary_v<_Tp&, const _Up> + explicit(!is_convertible_v<const _Up, _Tp&>) + constexpr + optional(const optional<_Up>&& __rhs) = delete; + + constexpr ~optional() = default; + + // Assignment. + constexpr optional& operator=(nullopt_t) noexcept + { + _M_val = nullptr; + return *this; + } + + constexpr optional& operator=(const optional&) noexcept = default; + + template<typename _Up> + requires is_constructible_v<_Tp&, _Up> + && (!reference_constructs_from_temporary_v<_Tp&, _Up>) + constexpr _Tp& + emplace(_Up&& __u) + noexcept(is_nothrow_constructible_v<_Tp&, _Up>) + { + __convert_ref_init_val(std::forward<_Up>(__u)); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4300. Missing Returns: element in optional<T&>::emplace + return *_M_val; + } + + // Swap. + constexpr void swap(optional& __rhs) noexcept + { std::swap(_M_val, __rhs._M_val); } + +#ifdef __cpp_lib_optional_range_support // >= C++26 + // Iterator support. + constexpr auto begin() const noexcept + requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>) + { return __gnu_cxx::__normal_iterator<_Tp*, optional>(_M_val); } + + constexpr auto end() const noexcept + requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>) + { return begin() + has_value(); } +#endif // __cpp_lib_optional_range_support + + // Observers. + constexpr _Tp* operator->() const noexcept + { + __glibcxx_assert(_M_val); // hardened precondition + return _M_val; + } + + constexpr _Tp& operator*() const noexcept + { + __glibcxx_assert(_M_val); // hardened precondition + return *_M_val; + } + + constexpr explicit operator bool() const noexcept + { + return _M_val; + } + + constexpr bool has_value() const noexcept + { + return _M_val; + } + + constexpr _Tp& value() const + { + if (_M_val) + return *_M_val; + __throw_bad_optional_access(); + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4304. std::optional<NonReturnable&> is ill-formed due to value_or + template<typename _Up = remove_cv_t<_Tp>> + requires is_object_v<_Tp> && (!is_array_v<_Tp>) + constexpr decay_t<_Tp> + value_or(_Up&& __u) const + { + using _Xp = remove_cv_t<_Tp>; + static_assert(is_convertible_v<_Tp&, _Xp>); + static_assert(is_convertible_v<_Up, _Xp>); + if (_M_val) + return *_M_val; + return std::forward<_Up>(__u); + } + + // Monadic operations. + template<typename _Fn> + constexpr auto + and_then(_Fn&& __f) const + { + using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp&>>; + static_assert(__is_optional_v<_Up>, + "the function passed to std::optional<T&>::and_then " + "must return a std::optional"); + if (has_value()) + return std::__invoke(std::forward<_Fn>(__f), *_M_val); + else + return _Up(); + } + + template<typename _Fn> + constexpr + optional<remove_cv_t<invoke_result_t<_Fn, _Tp&>>> + transform(_Fn&& __f) const + { + using _Up = remove_cv_t<invoke_result_t<_Fn, _Tp&>>; + if (has_value()) + return optional<_Up>(_Optional_func<_Fn>{__f}, *_M_val); + else + return optional<_Up>(); + } + + template<typename _Fn> + requires invocable<_Fn> + constexpr + optional + or_else(_Fn&& __f) const + { + static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Fn>>, optional>, + "the function passed to std::optional<T&>::or_else " + "must return a std::optional<T&>"); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4367. Improve optional<T&>::or_else + if (has_value()) + return *this; + else + return std::forward<_Fn>(__f)(); + } + + // Modifiers. + constexpr void reset() noexcept + { + _M_val = nullptr; + } + + private: + _Tp *_M_val = nullptr; + + [[__gnu__::__always_inline__]] + constexpr _Tp& + _M_fwd() const noexcept + { return *_M_val; } + + template<typename _Up> friend class optional; + + template<typename _Up> + constexpr + void + __convert_ref_init_val(_Up&& __u) + noexcept + { + _Tp& __r(std::forward<_Up>(__u)); + _M_val = std::addressof(__r); + } + + template<typename _Fn, typename _Value> + explicit constexpr + optional(_Optional_func<_Fn> __f, _Value&& __v) + { + _Tp& __r = std::__invoke(std::forward<_Fn>(__f._M_f), std::forward<_Value>(__v)); + _M_val = std::addressof(__r); + } + }; +#endif // __cpp_lib_optional >= 202506L + template<typename _Tp> using __optional_relop_t = enable_if_t<is_convertible_v<_Tp, bool>, bool>; @@ -1456,8 +1855,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator==(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_eq_t<_Tp, _Up> { - return static_cast<bool>(__lhs) == static_cast<bool>(__rhs) - && (!__lhs || *__lhs == *__rhs); + if (__lhs.has_value() != __rhs.has_value()) + return false; + if (!__lhs.has_value()) + return true; + return *__lhs == *__rhs; } template<typename _Tp, typename _Up> @@ -1465,8 +1867,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator!=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_ne_t<_Tp, _Up> { - return static_cast<bool>(__lhs) != static_cast<bool>(__rhs) - || (static_cast<bool>(__lhs) && *__lhs != *__rhs); + if (__lhs.has_value() != __rhs.has_value()) + return true; + if (!__lhs.has_value()) + return false; + return *__lhs != *__rhs; } template<typename _Tp, typename _Up> @@ -1474,7 +1879,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator<(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_lt_t<_Tp, _Up> { - return static_cast<bool>(__rhs) && (!__lhs || *__lhs < *__rhs); + if (!__rhs.has_value()) + return false; + if (!__lhs.has_value()) + return true; + return *__lhs < *__rhs; } template<typename _Tp, typename _Up> @@ -1482,7 +1891,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator>(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_gt_t<_Tp, _Up> { - return static_cast<bool>(__lhs) && (!__rhs || *__lhs > *__rhs); + if (!__lhs.has_value()) + return false; + if (!__rhs.has_value()) + return true; + return *__lhs > *__rhs; } template<typename _Tp, typename _Up> @@ -1490,7 +1903,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator<=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_le_t<_Tp, _Up> { - return !__lhs || (static_cast<bool>(__rhs) && *__lhs <= *__rhs); + if (!__lhs.has_value()) + return true; + if (!__rhs.has_value()) + return false; + return *__lhs <= *__rhs; } template<typename _Tp, typename _Up> @@ -1498,7 +1915,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator>=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) -> __optional_ge_t<_Tp, _Up> { - return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs); + if (!__rhs.has_value()) + return true; + if (!__lhs.has_value()) + return false; + return *__lhs >= *__rhs; } #ifdef __cpp_lib_three_way_comparison @@ -1595,84 +2016,132 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto operator== [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_eq_t<_Tp, _Up> - { return __lhs && *__lhs == __rhs; } + { + if (__lhs.has_value()) + return *__lhs == __rhs; + return false; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator== [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_eq_t<_Tp, _Up> - { return __rhs && __lhs == *__rhs; } + { + if (__rhs.has_value()) + return __lhs == *__rhs; + return false; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator!= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_ne_t<_Tp, _Up> - { return !__lhs || *__lhs != __rhs; } + { + if (__lhs.has_value()) + return *__lhs != __rhs; + return true; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator!= [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_ne_t<_Tp, _Up> - { return !__rhs || __lhs != *__rhs; } + { + if (__rhs.has_value()) + return __lhs != *__rhs; + return true; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator< [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_lt_t<_Tp, _Up> - { return !__lhs || *__lhs < __rhs; } + { + if (__lhs.has_value()) + return *__lhs < __rhs; + return true; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator< [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_lt_t<_Tp, _Up> - { return __rhs && __lhs < *__rhs; } + { + if (__rhs.has_value()) + return __lhs < *__rhs; + return false; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator> [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_gt_t<_Tp, _Up> - { return __lhs && *__lhs > __rhs; } + { + if (__lhs.has_value()) + return *__lhs > __rhs; + return false; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator> [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_gt_t<_Tp, _Up> - { return !__rhs || __lhs > *__rhs; } + { + if (__rhs.has_value()) + return __lhs > *__rhs; + return true; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator<= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_le_t<_Tp, _Up> - { return !__lhs || *__lhs <= __rhs; } + { + if (__lhs.has_value()) + return *__lhs <= __rhs; + return true; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator<= [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_le_t<_Tp, _Up> - { return __rhs && __lhs <= *__rhs; } + { + if (__rhs.has_value()) + return __lhs <= *__rhs; + return false; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Up) constexpr auto operator>= [[nodiscard]] (const optional<_Tp>& __lhs, const _Up& __rhs) -> __optional_ge_t<_Tp, _Up> - { return __lhs && *__lhs >= __rhs; } + { + if (__lhs.has_value()) + return *__lhs >= __rhs; + return false; + } template<typename _Tp, typename _Up> _REQUIRES_NOT_OPTIONAL(_Tp) constexpr auto operator>= [[nodiscard]] (const _Tp& __lhs, const optional<_Up>& __rhs) -> __optional_ge_t<_Tp, _Up> - { return !__rhs || __lhs >= *__rhs; } + { + if (__rhs.has_value()) + return __lhs >= *__rhs; + return true; + } #ifdef __cpp_lib_three_way_comparison // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -1703,17 +2172,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(noexcept(__lhs.swap(__rhs))) { __lhs.swap(__rhs); } +#if __cpp_lib_optional >= 202506L + // We deviate from standard, that do not declared separate swap overload + // from optional<T&>. + template<typename _Tp> + constexpr void + swap(optional<_Tp&>& __lhs, optional<_Tp&>& __rhs) noexcept + { __lhs.swap(__rhs); } +#endif + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2766. Swapping non-swappable types template<typename _Tp> enable_if_t<!(is_move_constructible_v<_Tp> && is_swappable_v<_Tp>)> swap(optional<_Tp>&, optional<_Tp>&) = delete; +#if __cpp_lib_optional >= 202506L + template<int = 0, typename _Tp> +#else template<typename _Tp> +#endif constexpr enable_if_t<is_constructible_v<decay_t<_Tp>, _Tp>, optional<decay_t<_Tp>>> make_optional(_Tp&& __t) noexcept(is_nothrow_constructible_v<optional<decay_t<_Tp>>, _Tp>) - { return optional<decay_t<_Tp>>{ std::forward<_Tp>(__t) }; } + { return optional<decay_t<_Tp>>( std::forward<_Tp>(__t) ); } template<typename _Tp, typename... _Args> constexpr @@ -1721,7 +2205,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION optional<_Tp>> make_optional(_Args&&... __args) noexcept(is_nothrow_constructible_v<_Tp, _Args...>) - { return optional<_Tp>{ in_place, std::forward<_Args>(__args)... }; } + { return optional<_Tp>( in_place, std::forward<_Args>(__args)... ); } template<typename _Tp, typename _Up, typename... _Args> constexpr @@ -1729,7 +2213,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION optional<_Tp>> make_optional(initializer_list<_Up> __il, _Args&&... __args) noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) - { return optional<_Tp>{ in_place, __il, std::forward<_Args>(__args)... }; } + { return optional<_Tp>( in_place, __il, std::forward<_Args>(__args)... ); } // Hash. @@ -1757,6 +2241,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> struct hash<optional<_Tp>> + // hash for optional<T&> is disabled because is_hash_enabled_for<T&> is false : public __conditional_t<__is_hash_enabled_for<remove_const_t<_Tp>>, __optional_hash<_Tp>, __hash_not_enabled<_Tp>> @@ -1772,6 +2257,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Tp> optional(_Tp) -> optional<_Tp>; #endif +#ifdef __cpp_lib_optional_range_support // >= C++26 + template<typename _Tp> + inline constexpr bool + ranges::enable_view<optional<_Tp>> = true; + +#if __cpp_lib_optional >= 202506L // C++26 + template<typename _Tp> + constexpr bool + ranges::enable_borrowed_range<optional<_Tp&>> = true; +#endif + + template<typename _Tp> + inline constexpr range_format + format_kind<optional<_Tp>> = range_format::disabled; +#endif // __cpp_lib_optional_range_support + #undef _GLIBCXX_USE_CONSTRAINTS_FOR_OPTIONAL _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream index 644e568..3387296 100644 --- a/libstdc++-v3/include/std/ostream +++ b/libstdc++-v3/include/std/ostream @@ -193,7 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __format::_Str_sink<char> __buf; std::vformat_to(__buf.out(), __os.getloc(), __fmt, __args); - auto __out = __buf.view(); + auto __out = __buf._M_span(); void* __open_terminal(streambuf*); error_code __write_to_terminal(void*, span<char>); @@ -259,9 +259,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION print(ostream& __os, format_string<_Args...> __fmt, _Args&&... __args) { auto __fmtargs = std::make_format_args(__args...); +#if defined(_WIN32) && !defined(__CYGWIN__) if constexpr (__unicode::__literal_encoding_is_utf8()) std::vprint_unicode(__os, __fmt.get(), __fmtargs); else +#endif std::vprint_nonunicode(__os, __fmt.get(), __fmtargs); } @@ -269,10 +271,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline void println(ostream& __os, format_string<_Args...> __fmt, _Args&&... __args) { - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 4088. println ignores the locale imbued in std::ostream - std::print(__os, "{}\n", std::format(__os.getloc(), __fmt, - std::forward<_Args>(__args)...)); + auto __fmtargs = std::make_format_args(__args...); + std::string __fmtn; + __fmtn.reserve(__fmt.get().size() + 1); + __fmtn = __fmt.get(); + __fmtn += '\n'; +#if defined(_WIN32) && !defined(__CYGWIN__) + if constexpr (__unicode::__literal_encoding_is_utf8()) + std::vprint_unicode(__os, __fmtn, __fmtargs); + else +#endif + std::vprint_nonunicode(__os, __fmtn, __fmtargs); } // Defined for C++26, supported as an extension to C++23. diff --git a/libstdc++-v3/include/std/print b/libstdc++-v3/include/std/print index ea1aaac..6ffd9a4 100644 --- a/libstdc++-v3/include/std/print +++ b/libstdc++-v3/include/std/print @@ -53,9 +53,214 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION +namespace __format +{ +#if _GLIBCXX_USE_STDIO_LOCKING && _GLIBCXX_USE_GLIBC_STDIO_EXT + // These are defined in <stdio_ext.h> but we don't want to include that. + extern "C" int __fwritable(FILE*) noexcept; + extern "C" int __flbf(FILE*) noexcept; + extern "C" size_t __fbufsize(FILE*) noexcept; + + // A format sink that writes directly to a Glibc FILE. + // The file is locked on construction and its buffer is accessed directly. + class _File_sink final : _Buf_sink<char> + { + struct _File + { + explicit + _File(FILE* __f) : _M_file(__f) + { + ::flockfile(__f); + // Ensure stream is in write mode + if (!__fwritable(__f)) + { + ::funlockfile(__f); + __throw_system_error(EACCES); + } + // Allocate buffer if needed: + if (_M_write_buf().empty()) + if (::__overflow(__f, EOF) == EOF) + { + const int __err = errno; + ::funlockfile(__f); + __throw_system_error(__err); + } + } + + ~_File() { ::funlockfile(_M_file); } + + _File(_File&&) = delete; + + // A span viewing the unused portion of the stream's output buffer. + std::span<char> + _M_write_buf() noexcept + { + return {_M_file->_IO_write_ptr, + size_t(_M_file->_IO_buf_end - _M_file->_IO_write_ptr)}; + } + + // Flush the output buffer to the file so we can write to it again. + void + _M_flush() + { + if (::fflush_unlocked(_M_file)) + __throw_system_error(errno); + } + + // Update the current position in the output buffer. + void + _M_bump(size_t __n) noexcept + { _M_file->_IO_write_ptr += __n; } + + bool + _M_line_buffered() const noexcept + { return __flbf(_M_file); } // Or: _M_file->_flags & 0x200 + + bool + _M_unbuffered() const noexcept + { return __fbufsize(_M_file) == 1; } // Or: _M_file->_flags & 0x2 + + FILE* _M_file; + } _M_file; + + bool _M_add_newline; // True for std::println, false for std::print. + + // Flush the stream's put area so it can be refilled. + void + _M_overflow() override + { + auto __s = this->_M_used(); + if (__s.data() == this->_M_buf) + { + // Characters in internal buffer need to be transferred to the FILE. + auto __n = ::fwrite_unlocked(__s.data(), 1, __s.size(), + _M_file._M_file); + if (__n != __s.size()) + __throw_system_error(errno); + this->_M_reset(this->_M_buf); + } + else + { + // Characters were written directly to the FILE's output buffer. + _M_file._M_bump(__s.size()); + _M_file._M_flush(); + this->_M_reset(_M_file._M_write_buf()); + } + } + + public: + _File_sink(FILE* __f, bool __add_newline) + : _M_file(__f), _M_add_newline(__add_newline) + { + if (!_M_file._M_unbuffered()) + // Write directly to the FILE's output buffer. + this->_M_reset(_M_file._M_write_buf()); + } + + ~_File_sink() noexcept(false) + { + auto __s = this->_M_used(); + if (__s.data() == this->_M_buf) // Unbuffered stream + { + _File_sink::_M_overflow(); + if (_M_add_newline) + ::putc_unlocked('\n', _M_file._M_file); + } + else + { + _M_file._M_bump(__s.size()); + if (_M_add_newline) + ::putc_unlocked('\n', _M_file._M_file); + else if (_M_file._M_line_buffered() && __s.size() + && (__s.back() == '\n' + || __builtin_memchr(__s.data(), '\n', __s.size()))) + _M_file._M_flush(); + } + } + + using _Sink<char>::out; + }; +#elif _GLIBCXX_USE_STDIO_LOCKING + // A format sink that buffers output and then copies it to a stdio FILE. + // The file is locked on construction and written to using fwrite_unlocked. + class _File_sink final : _Buf_sink<char> + { + FILE* _M_file; + bool _M_add_newline; + + // Transfer buffer contents to the FILE, so buffer can be refilled. + void + _M_overflow() override + { + auto __s = this->_M_used(); +#if _GLIBCXX_HAVE_FWRITE_UNLOCKED + auto __n = ::fwrite_unlocked(__s.data(), 1, __s.size(), _M_file); + if (__n != __s.size()) + __throw_system_error(errno); +#else + for (char __c : __s) + ::putc_unlocked(__c, _M_file); + if (::ferror(_M_file)) + __throw_system_error(errno); +#endif + this->_M_reset(this->_M_buf); + } + + public: + _File_sink(FILE* __f, bool __add_newline) noexcept + : _Buf_sink<char>(), _M_file(__f), _M_add_newline(__add_newline) + { ::flockfile(__f); } + + ~_File_sink() noexcept(false) + { + _File_sink::_M_overflow(); + if (_M_add_newline) + ::putc_unlocked('\n', _M_file); + ::funlockfile(_M_file); + } + + using _Sink<char>::out; + }; +#else + // A wrapper around a format sink that copies the output to a stdio FILE. + // This is not actually a _Sink itself, but it creates one to hold the + // formatted characters and then copies them to the file when finished. + class _File_sink final + { + FILE* _M_file; + _Str_sink<char> _M_sink; + bool _M_add_newline; + + public: + _File_sink(FILE* __f, bool __add_newline) noexcept + : _M_file(__f), _M_add_newline(__add_newline) + { } + + ~_File_sink() noexcept(false) + { + string __s = std::move(_M_sink).get(); + if (_M_add_newline) + __s += '\n'; + auto __n = std::fwrite(__s.data(), 1, __s.size(), _M_file); + if (__n < __s.size()) + __throw_system_error(EIO); + } + + auto out() { return _M_sink.out(); } + }; +#endif +} // namespace __format + inline void vprint_nonunicode(FILE* __stream, string_view __fmt, format_args __args) { + std::vformat_to(__format::_File_sink(__stream, false).out(), __fmt, __args); + } + + inline void + vprint_nonunicode_buffered(FILE* __stream, string_view __fmt, + format_args __args) + { __format::_Str_sink<char> __buf; std::vformat_to(__buf.out(), __fmt, __args); auto __out = __buf.view(); @@ -73,14 +278,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #else __format::_Str_sink<char> __buf; std::vformat_to(__buf.out(), __fmt, __args); - auto __out = __buf.view(); + auto __out = __buf._M_span(); void* __open_terminal(FILE*); error_code __write_to_terminal(void*, span<char>); // If stream refers to a terminal, write a native Unicode string to it. if (auto __term = __open_terminal(__stream)) { - string __out = std::vformat(__fmt, __args); error_code __e; if (!std::fflush(__stream)) { @@ -95,21 +299,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_THROW_OR_ABORT(system_error(__e, "std::vprint_unicode")); } - // Otherwise just write the string to the file as vprint_nonunicode does. + // Otherwise just write the string to the file. if (std::fwrite(__out.data(), 1, __out.size(), __stream) != __out.size()) __throw_system_error(EIO); #endif } + inline void + vprint_unicode_buffered(FILE* __stream, string_view __fmt, format_args __args) + { +#if !defined(_WIN32) || defined(__CYGWIN__) + // For most targets we don't need to do anything special to write + // Unicode to a terminal. Just use the nonunicode function. + std::vprint_nonunicode_buffered(__stream, __fmt, __args); +#else + // For Windows the locking function formats everything first anyway, + // so no formatting happens while a lock is taken. Just use that. + std::vprint_unicode(__stream, __fmt, __args); +#endif + } + template<typename... _Args> inline void print(FILE* __stream, format_string<_Args...> __fmt, _Args&&... __args) { + constexpr bool __locksafe = + (enable_nonlocking_formatter_optimization<remove_cvref_t<_Args>> && ...); + auto __fmtargs = std::make_format_args(__args...); +#if defined(_WIN32) && !defined(__CYGWIN__) if constexpr (__unicode::__literal_encoding_is_utf8()) - std::vprint_unicode(__stream, __fmt.get(), __fmtargs); + std::vprint_unicode_buffered(__stream, __fmt.get(), __fmtargs); else +#endif + + if constexpr (__locksafe) std::vprint_nonunicode(__stream, __fmt.get(), __fmtargs); + else + std::vprint_nonunicode_buffered(__stream, __fmt.get(), __fmtargs); } template<typename... _Args> @@ -121,8 +348,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline void println(FILE* __stream, format_string<_Args...> __fmt, _Args&&... __args) { - std::print(__stream, "{}\n", - std::format(__fmt, std::forward<_Args>(__args)...)); + constexpr bool __locksafe = + (enable_nonlocking_formatter_optimization<remove_cvref_t<_Args>> && ...); + + // The standard wants us to call + // print(stream, runtime_format(string(fmt.get()) + '\n'), args...) + // here, but we can avoid that string concatenation in most cases, + // and we know what that would call, so we can call that directly. + + auto __fmtargs = std::make_format_args(__args...); +#if defined(_WIN32) && !defined(__CYGWIN__) + if constexpr (__unicode::__literal_encoding_is_utf8()) + { + // We can't avoid the string concatenation here, but we can call + // vprint_unicode_buffered directly, since that's what print would do. + string __fmtn; + __fmtn.reserve(__fmt.get().size() + 1); + __fmtn = __fmt.get(); + __fmtn += '\n'; + std::vprint_unicode_buffered(__stream, __fmtn, __fmtargs); + } + else +#endif + + // For non-Windows and for non-Unicode on Windows, we know that print + // would call vprint_nonunicode or vprint_nonunicode_buffered with a + // newline appended to the format-string. Use a _File_sink that adds + // the newline automatically and write to it directly. + if constexpr (__locksafe) + std::vformat_to(__format::_File_sink(__stream, true).out(), + __fmt.get(), __fmtargs); + else + { + // Format to a string buffer first, then write the result to a + // _File_sink that adds a newline. + __format::_Str_sink<char> __buf; + std::vformat_to(__buf.out(), __fmt.get(), __fmtargs); + string_view __s(__buf.view()); + __format::_File_sink(__stream, true).out() = __s; + } } template<typename... _Args> @@ -131,19 +395,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { std::println(stdout, __fmt, std::forward<_Args>(__args)...); } inline void - vprint_unicode(string_view __fmt, format_args __args) - { std::vprint_unicode(stdout, __fmt, __args); } + vprint_unicode_buffered(string_view __fmt, format_args __args) + { std::vprint_unicode_buffered(stdout, __fmt, __args); } inline void - vprint_nonunicode(string_view __fmt, format_args __args) - { std::vprint_nonunicode(stdout, __fmt, __args); } + vprint_nonunicode_buffered(string_view __fmt, format_args __args) + { std::vprint_nonunicode_buffered(stdout, __fmt, __args); } // Defined for C++26, supported as an extension to C++23. inline void println(FILE* __stream) { #if defined(_WIN32) && !defined(__CYGWIN__) if constexpr (__unicode::__literal_encoding_is_utf8()) - std::vprint_unicode(__stream, "\n", std::make_format_args()); + std::vprint_unicode_buffered(__stream, "\n", std::make_format_args()); else #endif if (std::putc('\n', __stream) == EOF) diff --git a/libstdc++-v3/include/std/queue b/libstdc++-v3/include/std/queue index c06a4c3..bf2b344 100644 --- a/libstdc++-v3/include/std/queue +++ b/libstdc++-v3/include/std/queue @@ -61,13 +61,111 @@ #include <bits/requires_hosted.h> // containers +#define __glibcxx_want_adaptor_iterator_pair_constructor +#define __glibcxx_want_containers_ranges +#include <bits/version.h> + #include <deque> #include <vector> #include <bits/stl_heap.h> #include <bits/stl_function.h> #include <bits/stl_queue.h> -#define __glibcxx_want_adaptor_iterator_pair_constructor -#include <bits/version.h> +#ifdef __glibcxx_format_ranges // C++ >= 23 && HOSTED +#include <bits/formatfwd.h> + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + // Standard does not constrain accepted _CharT, we do so we can + // befriend specializations. + template<__format::__char _CharT, typename _Tp, + formattable<_CharT> _Container> + struct formatter<queue<_Tp, _Container>, _CharT> + { + private: + using __maybe_const_adaptor + = __conditional_t< + __format::__const_formattable_range<_Container, _CharT>, + const queue<_Tp, _Container>, queue<_Tp, _Container>>; + + public: + // Standard declares this as template accepting unconstrained + // ParseContext type. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + // Standard declares this as template accepting unconstrained + // FormatContext type. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__maybe_const_adaptor& __a, + basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format(__a.c, __fc); } + + private: + // Standard uses formatter<ref_view<_Container>, _CharT>, but range_formatter + // provides same behavior. + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3881. Incorrect formatting of container adapters backed by std::string + range_formatter<_Tp, _CharT> _M_f; + }; + +#if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4398. enable_nonlocking_formatter_optimization should be disabled for container adaptors + template<typename _Tp, typename _Container> + constexpr bool + enable_nonlocking_formatter_optimization<queue<_Tp, _Container>> = false; +#endif + + template<__format::__char _CharT, typename _Tp, + formattable<_CharT> _Container, typename _Compare> + struct formatter<priority_queue<_Tp, _Container, _Compare>, _CharT> + { + private: + using __maybe_const_adaptor + = __conditional_t< + __format::__const_formattable_range<_Container, _CharT>, + const priority_queue<_Tp, _Container, _Compare>, + priority_queue<_Tp, _Container, _Compare>>; + + public: + // Standard declares this as template accepting unconstrained + // ParseContext type. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.parse(__pc); } + + // Standard declares this as template accepting unconstrained + // FormatContext type. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(__maybe_const_adaptor& __a, + basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format(__a.c, __fc); } + + private: + // Standard uses formatter<ref_view<_Container>, _CharT>, but range_formatter + // provides same behavior. + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3881. Incorrect formatting of container adapters backed by std::string + range_formatter<_Tp, _CharT> _M_f; + }; + +#if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4398. enable_nonlocking_formatter_optimization should be disabled for container adaptors + template<typename _Tp, typename _Container, typename _Comparator> + constexpr bool + enable_nonlocking_formatter_optimization< + priority_queue<_Tp, _Container, _Comparator>> = false; +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // __glibcxx_format_ranges + #endif /* _GLIBCXX_QUEUE */ diff --git a/libstdc++-v3/include/std/random b/libstdc++-v3/include/std/random index 0e058a0..8a02ade 100644 --- a/libstdc++-v3/include/std/random +++ b/libstdc++-v3/include/std/random @@ -39,6 +39,9 @@ # include <bits/c++0x_warning.h> #else +#define __glibcxx_want_philox_engine +#include <bits/version.h> + #include <cmath> #include <cstdint> // For uint_fast32_t, uint_fast64_t, uint_least32_t #include <cstdlib> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 7a339c5..b81ee78 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -51,6 +51,7 @@ #include <utility> #include <variant> #endif +#include <bits/binders.h> #include <bits/ranges_util.h> #include <bits/refwrap.h> @@ -64,7 +65,7 @@ #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_indices #define __glibcxx_want_ranges_join_with #define __glibcxx_want_ranges_repeat #define __glibcxx_want_ranges_slide @@ -285,6 +286,190 @@ namespace ranges operator->() const noexcept { return std::__addressof(_M_value); } }; + + template<template<typename> class> + constexpr bool __is_std_op_template = false; + + template<> + inline constexpr bool __is_std_op_template<std::equal_to> = true; + template<> + inline constexpr bool __is_std_op_template<std::not_equal_to> = true; + template<> + inline constexpr bool __is_std_op_template<std::greater> = true; + template<> + inline constexpr bool __is_std_op_template<std::less> = true; + template<> + inline constexpr bool __is_std_op_template<std::greater_equal> = true; + template<> + inline constexpr bool __is_std_op_template<std::less_equal> = true; + template<> + inline constexpr bool __is_std_op_template<std::plus> = true; + template<> + inline constexpr bool __is_std_op_template<std::minus> = true; + template<> + inline constexpr bool __is_std_op_template<std::multiplies> = true; + template<> + inline constexpr bool __is_std_op_template<std::divides> = true; + template<> + inline constexpr bool __is_std_op_template<std::modulus> = true; + template<> + inline constexpr bool __is_std_op_template<std::negate> = true; + template<> + inline constexpr bool __is_std_op_template<std::logical_and> = true; + template<> + inline constexpr bool __is_std_op_template<std::logical_or> = true; + template<> + inline constexpr bool __is_std_op_template<std::logical_not> = true; + template<> + inline constexpr bool __is_std_op_template<std::bit_and> = true; + template<> + inline constexpr bool __is_std_op_template<std::bit_or> = true; + template<> + inline constexpr bool __is_std_op_template<std::bit_xor> = true; + template<> + inline constexpr bool __is_std_op_template<std::bit_not> = true; + + + template<typename _Fn> + constexpr bool __is_std_op_wrapper = false; + + template<template<typename> class _Ft, typename _Tp> + constexpr bool __is_std_op_wrapper<_Ft<_Tp>> + = __is_std_op_template<_Ft>; + + namespace __func_handle + { + template<typename _Fn> + struct _Inplace + { + _Inplace() = default; + + constexpr explicit + _Inplace(_Fn __func) noexcept + : _M_fn(__func) + { } + + template<typename... _Iters> + constexpr decltype(auto) + _M_call_deref(const _Iters&... __iters) const + noexcept(noexcept(_M_fn(*__iters...))) + { return _M_fn(*__iters...); } + + template<typename _DistType, typename... _Iters> + constexpr decltype(auto) + _M_call_subscript(const _DistType __n, const _Iters&... __iters) const + noexcept(noexcept(_M_fn(__iters[iter_difference_t<_Iters>(__n)]...))) + { return _M_fn(__iters[iter_difference_t<_Iters>(__n)]...); } + + private: + [[no_unique_address]] _Fn _M_fn = _Fn(); + }; + + template<typename _Fn> + struct _InplaceMemPtr + { + _InplaceMemPtr() = default; + + constexpr explicit + _InplaceMemPtr(_Fn __func) noexcept + : _M_ptr(__func) + {} + + template<typename... _Iters> + constexpr decltype(auto) + _M_call_deref(const _Iters&... __iters) const + noexcept(noexcept(std::__invoke(_M_ptr, *__iters...))) + { return std::__invoke(_M_ptr, *__iters...); } + + template<typename _DistType, typename... _Iters> + constexpr decltype(auto) + _M_call_subscript(const _DistType __n, const _Iters&... __iters) const + noexcept(noexcept(std::__invoke(_M_ptr, __iters[iter_difference_t<_Iters>(__n)]...))) + { return std::__invoke(_M_ptr, __iters[iter_difference_t<_Iters>(__n)]...); } + + private: + _Fn _M_ptr = nullptr; + }; + + template<typename _Fn> + struct _ViaPointer + { + _ViaPointer() = default; + + constexpr explicit + _ViaPointer(_Fn& __func) noexcept + : _M_ptr(std::addressof(__func)) + { } + + template<typename _Un> + requires (!is_const_v<_Un>) && is_same_v<const _Un, _Fn> + constexpr + _ViaPointer(_ViaPointer<_Un> __other) noexcept + : _M_ptr(__other._M_ptr) + { } + + template<typename... _Iters> + constexpr decltype(auto) + _M_call_deref(const _Iters&... __iters) const + noexcept(noexcept((*_M_ptr)(*__iters...))) + { return (*_M_ptr)(*__iters...); } + + template<typename _DistType, typename... _Iters> + constexpr decltype(auto) + _M_call_subscript(const _DistType __n, const _Iters&... __iters) const + noexcept(noexcept((*_M_ptr)(__iters[iter_difference_t<_Iters>(__n)]...))) + { return (*_M_ptr)(__iters[iter_difference_t<_Iters>(__n)]...); } + + private: + _Fn* _M_ptr = nullptr; + + template<typename> + friend struct _ViaPointer; + }; + + template<typename _Fn> + struct _StaticCall + { + _StaticCall() = default; + + constexpr explicit + _StaticCall(const _Fn&) noexcept + {} + + template<typename... _Iters> + static constexpr decltype(auto) + _M_call_deref(const _Iters&... __iters) + noexcept(noexcept(_Fn::operator()(*__iters...))) + { return _Fn::operator()(*__iters...); } + + template<typename _DistType, typename... _Iters> + static constexpr decltype(auto) + _M_call_subscript(_DistType __n, const _Iters&... __iters) + noexcept(noexcept(_Fn::operator()(__iters[iter_difference_t<_Iters>(__n)]...))) + { return _Fn::operator()(__iters[iter_difference_t<_Iters>(__n)]...); } + }; + + template<typename _Fn, typename... _Iters> + consteval auto + __select() + { + using _Fd = remove_cv_t<_Fn>; + if constexpr (is_member_pointer_v<_Fd>) + return __func_handle::_InplaceMemPtr<_Fd>(); + else if constexpr (is_function_v<remove_pointer_t<_Fd>>) + return __func_handle::_Inplace<_Fd>(); + else if constexpr (__is_std_op_wrapper<_Fd>) + return __func_handle::_Inplace<_Fd>(); + else if constexpr (requires (const _Iters&... __iters) + { _Fd::operator()(*__iters...); }) + return __func_handle::_StaticCall<_Fd>(); + else + return __func_handle::_ViaPointer<_Fn>(); + }; + } // __func_handle + + template<typename _Fn, typename... _Iters> + using __func_handle_t = decltype(__func_handle::__select<_Fn, _Iters...>()); } // namespace __detail /// A view that contains exactly one element. @@ -661,7 +846,7 @@ namespace ranges : _M_value(__value) { } - constexpr + constexpr explicit iota_view(type_identity_t<_Winc> __value, type_identity_t<_Bound> __bound) : _M_value(__value), _M_bound(__bound) @@ -670,19 +855,19 @@ namespace ranges __glibcxx_assert( bool(__value <= __bound) ); } - constexpr + constexpr explicit iota_view(_Iterator __first, _Iterator __last) requires same_as<_Winc, _Bound> : iota_view(__first._M_value, __last._M_value) { } - constexpr + constexpr explicit iota_view(_Iterator __first, unreachable_sentinel_t __last) requires same_as<_Bound, unreachable_sentinel_t> : iota_view(__first._M_value, __last) { } - constexpr + constexpr explicit iota_view(_Iterator __first, _Sentinel __last) requires (!same_as<_Winc, _Bound>) && (!same_as<_Bound, unreachable_sentinel_t>) : iota_view(__first._M_value, __last._M_bound) @@ -785,6 +970,19 @@ namespace views }; inline constexpr _Iota iota{}; + +#ifdef __cpp_lib_ranges_indices // C++ >= 26 + struct _Indices + { + template<ranges::__detail::__is_integer_like _Tp> + requires __detail::__can_iota_view<_Tp> + [[nodiscard]] constexpr auto + operator() (_Tp __e) const noexcept + { return iota(_Tp{}, __e); } + }; + + inline constexpr _Indices indices{}; +#endif // __cpp_lib_ranges_indices } // namespace views #if _GLIBCXX_HOSTED @@ -1048,93 +1246,43 @@ namespace views::__adaptor template<typename _Adaptor, typename... _Args> struct _Partial : _RangeAdaptorClosure<_Partial<_Adaptor, _Args...>> { - tuple<_Args...> _M_args; + using _Binder = _Bind_back_t<_Adaptor, _Args...>; + [[no_unique_address]] _Binder _M_binder; // First parameter is to ensure this constructor is never used // instead of the copy/move constructor. template<typename... _Ts> constexpr _Partial(int, _Ts&&... __args) - : _M_args(std::forward<_Ts>(__args)...) + : _M_binder(0, _Adaptor(), std::forward<_Ts>(__args)...) { } // Invoke _Adaptor with arguments __r, _M_args... according to the // value category of this _Partial object. -#if __cpp_explicit_this_parameter +#if _GLIBCXX_EXPLICIT_THIS_PARAMETER +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this template<typename _Self, typename _Range> requires __adaptor_invocable<_Adaptor, _Range, __like_t<_Self, _Args>...> constexpr auto operator()(this _Self&& __self, _Range&& __r) { - auto __forwarder = [&__r] (auto&&... __args) { - return _Adaptor{}(std::forward<_Range>(__r), - std::forward<decltype(__args)>(__args)...); - }; - return std::apply(__forwarder, __like_t<_Self, _Partial>(__self)._M_args); + return _Binder::_S_call(__like_t<_Self, _Partial>(__self)._M_binder, + std::forward<_Range>(__r)); } +# pragma GCC diagnostic pop #else template<typename _Range> requires __adaptor_invocable<_Adaptor, _Range, const _Args&...> constexpr auto operator()(_Range&& __r) const & - { - auto __forwarder = [&__r] (const auto&... __args) { - return _Adaptor{}(std::forward<_Range>(__r), __args...); - }; - return std::apply(__forwarder, _M_args); - } + { return _Binder::_S_call(_M_binder, std::forward<_Range>(__r)); } template<typename _Range> requires __adaptor_invocable<_Adaptor, _Range, _Args...> constexpr auto operator()(_Range&& __r) && - { - auto __forwarder = [&__r] (auto&... __args) { - return _Adaptor{}(std::forward<_Range>(__r), std::move(__args)...); - }; - return std::apply(__forwarder, _M_args); - } - - template<typename _Range> - constexpr auto - operator()(_Range&& __r) const && = delete; -#endif - }; - - // A lightweight specialization of the above primary template for - // the common case where _Adaptor accepts a single extra argument. - template<typename _Adaptor, typename _Arg> - struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure<_Partial<_Adaptor, _Arg>> - { - _Arg _M_arg; - - template<typename _Tp> - constexpr - _Partial(int, _Tp&& __arg) - : _M_arg(std::forward<_Tp>(__arg)) - { } - -#if __cpp_explicit_this_parameter - template<typename _Self, typename _Range> - requires __adaptor_invocable<_Adaptor, _Range, __like_t<_Self, _Arg>> - constexpr auto - operator()(this _Self&& __self, _Range&& __r) - { - return _Adaptor{}(std::forward<_Range>(__r), - __like_t<_Self, _Partial>(__self)._M_arg); - } -#else - template<typename _Range> - requires __adaptor_invocable<_Adaptor, _Range, const _Arg&> - constexpr auto - operator()(_Range&& __r) const & - { return _Adaptor{}(std::forward<_Range>(__r), _M_arg); } - - template<typename _Range> - requires __adaptor_invocable<_Adaptor, _Range, _Arg> - constexpr auto - operator()(_Range&& __r) && - { return _Adaptor{}(std::forward<_Range>(__r), std::move(_M_arg)); } + { return _Binder::_S_call(std::move(_M_binder), std::forward<_Range>(__r)); } template<typename _Range> constexpr auto @@ -1151,12 +1299,13 @@ namespace views::__adaptor && (is_trivially_copy_constructible_v<_Args> && ...) struct _Partial<_Adaptor, _Args...> : _RangeAdaptorClosure<_Partial<_Adaptor, _Args...>> { - tuple<_Args...> _M_args; + using _Binder = _Bind_back_t<_Adaptor, _Args...>; + [[no_unique_address]] _Binder _M_binder; template<typename... _Ts> constexpr _Partial(int, _Ts&&... __args) - : _M_args(std::forward<_Ts>(__args)...) + : _M_binder(0, _Adaptor(), std::forward<_Ts>(__args)...) { } // Invoke _Adaptor with arguments __r, const _M_args&... regardless @@ -1165,36 +1314,7 @@ namespace views::__adaptor requires __adaptor_invocable<_Adaptor, _Range, const _Args&...> constexpr auto operator()(_Range&& __r) const - { - auto __forwarder = [&__r] (const auto&... __args) { - return _Adaptor{}(std::forward<_Range>(__r), __args...); - }; - return std::apply(__forwarder, _M_args); - } - - static constexpr bool _S_has_simple_call_op = true; - }; - - // A lightweight specialization of the above template for the common case - // where _Adaptor accepts a single extra argument. - template<typename _Adaptor, typename _Arg> - requires __adaptor_has_simple_extra_args<_Adaptor, _Arg> - && is_trivially_copy_constructible_v<_Arg> - struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure<_Partial<_Adaptor, _Arg>> - { - _Arg _M_arg; - - template<typename _Tp> - constexpr - _Partial(int, _Tp&& __arg) - : _M_arg(std::forward<_Tp>(__arg)) - { } - - template<typename _Range> - requires __adaptor_invocable<_Adaptor, _Range, const _Arg&> - constexpr auto - operator()(_Range&& __r) const - { return _Adaptor{}(std::forward<_Range>(__r), _M_arg); } + { return _Binder::_S_call(_M_binder, std::forward<_Range>(__r)); } static constexpr bool _S_has_simple_call_op = true; }; @@ -1219,7 +1339,9 @@ namespace views::__adaptor // Invoke _M_rhs(_M_lhs(__r)) according to the value category of this // range adaptor closure object. -#if __cpp_explicit_this_parameter +#if _GLIBCXX_EXPLICIT_THIS_PARAMETER +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this template<typename _Self, typename _Range> requires __pipe_invocable<__like_t<_Self, _Lhs>, __like_t<_Self, _Rhs>, _Range> constexpr auto @@ -1229,6 +1351,7 @@ namespace views::__adaptor (__like_t<_Self, _Pipe>(__self)._M_lhs (std::forward<_Range>(__r)))); } +# pragma GCC diagnostic pop #else template<typename _Range> requires __pipe_invocable<const _Lhs&, const _Rhs&, _Range> @@ -1586,8 +1709,6 @@ namespace views::__adaptor }; template<random_access_range _Range> - requires (sizeof(range_difference_t<_Range>) - <= sizeof(iterator_t<_Range>)) struct _CachedPosition<_Range> { private: @@ -1812,7 +1933,7 @@ namespace views::__adaptor && default_initializable<_Pred>) = default; - constexpr + constexpr explicit filter_view(_Vp __base, _Pred __pred) : _M_base(std::move(__base)), _M_pred(std::move(__pred)) { } @@ -1943,6 +2064,10 @@ namespace views::__adaptor private: using _Parent = __detail::__maybe_const_t<_Const, transform_view>; using _Base = transform_view::_Base<_Const>; + using _Base_iter = iterator_t<_Base>; + using _Func_handle = __detail::__func_handle_t< + __detail::__maybe_const_t<_Const, _Fp>, + _Base_iter>; static auto _S_iter_concept() @@ -1957,10 +2082,8 @@ namespace views::__adaptor return input_iterator_tag{}; } - using _Base_iter = iterator_t<_Base>; - _Base_iter _M_current = _Base_iter(); - _Parent* _M_parent = nullptr; + [[no_unique_address]] _Func_handle _M_fun; public: using iterator_concept = decltype(_S_iter_concept()); @@ -1973,16 +2096,20 @@ namespace views::__adaptor _Iterator() requires default_initializable<_Base_iter> = default; constexpr - _Iterator(_Parent* __parent, _Base_iter __current) - : _M_current(std::move(__current)), - _M_parent(__parent) + _Iterator(_Func_handle __fun, _Base_iter __current) + : _M_current(std::move(__current)), _M_fun(__fun) { } constexpr + _Iterator(_Parent* __parent, _Base_iter __current) + : _M_current(std::move(__current)), _M_fun(*__parent->_M_fun) + {} + + constexpr _Iterator(_Iterator<!_Const> __i) requires _Const && convertible_to<iterator_t<_Vp>, _Base_iter> - : _M_current(std::move(__i._M_current)), _M_parent(__i._M_parent) + : _M_current(std::move(__i._M_current)), _M_fun(__i._M_fun) { } constexpr const _Base_iter& @@ -1995,8 +2122,8 @@ namespace views::__adaptor constexpr decltype(auto) operator*() const - noexcept(noexcept(std::__invoke(*_M_parent->_M_fun, *_M_current))) - { return std::__invoke(*_M_parent->_M_fun, *_M_current); } + noexcept(noexcept(_M_fun._M_call_deref(_M_current))) + { return _M_fun._M_call_deref(_M_current); } constexpr _Iterator& operator++() @@ -2049,7 +2176,7 @@ namespace views::__adaptor constexpr decltype(auto) operator[](difference_type __n) const requires random_access_range<_Base> - { return std::__invoke(*_M_parent->_M_fun, _M_current[__n]); } + { return _M_fun._M_call_subscript(__n, _M_current); } friend constexpr bool operator==(const _Iterator& __x, const _Iterator& __y) @@ -2087,17 +2214,17 @@ namespace views::__adaptor friend constexpr _Iterator operator+(_Iterator __i, difference_type __n) requires random_access_range<_Base> - { return {__i._M_parent, __i._M_current + __n}; } + { return {__i._M_fun, __i._M_current + __n}; } friend constexpr _Iterator operator+(difference_type __n, _Iterator __i) requires random_access_range<_Base> - { return {__i._M_parent, __i._M_current + __n}; } + { return {__i._M_fun, __i._M_current + __n}; } friend constexpr _Iterator operator-(_Iterator __i, difference_type __n) requires random_access_range<_Base> - { return {__i._M_parent, __i._M_current - __n}; } + { return {__i._M_fun, __i._M_current - __n}; } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3483. transform_view::iterator's difference is overconstrained @@ -2189,7 +2316,7 @@ namespace views::__adaptor && default_initializable<_Fp>) = default; - constexpr + constexpr explicit transform_view(_Vp __base, _Fp __fun) : _M_base(std::move(__base)), _M_fun(std::move(__fun)) { } @@ -2324,7 +2451,7 @@ namespace views::__adaptor public: take_view() requires default_initializable<_Vp> = default; - constexpr + constexpr explicit take_view(_Vp __base, range_difference_t<_Vp> __count) : _M_base(std::move(__base)), _M_count(std::move(__count)) { } @@ -2472,6 +2599,10 @@ namespace views::__adaptor using _Tp = remove_cvref_t<_Range>; if constexpr (__detail::__is_empty_view<_Tp>) return _Tp(); +#ifdef __cpp_lib_optional_range_support // >= C++26 + else if constexpr (__is_optional_v<_Tp> && view<_Tp>) + return __n ? std::forward<_Range>(__r) : _Tp(); +#endif else if constexpr (random_access_range<_Tp> && sized_range<_Tp> && (std::__detail::__is_span<_Tp> @@ -2563,7 +2694,7 @@ namespace views::__adaptor && default_initializable<_Pred>) = default; - constexpr + constexpr explicit take_while_view(_Vp __base, _Pred __pred) : _M_base(std::move(__base)), _M_pred(std::move(__pred)) { } @@ -2651,7 +2782,7 @@ namespace views::__adaptor public: drop_view() requires default_initializable<_Vp> = default; - constexpr + constexpr explicit drop_view(_Vp __base, range_difference_t<_Vp> __count) : _M_base(std::move(__base)), _M_count(__count) { __glibcxx_assert(__count >= 0); } @@ -2748,6 +2879,10 @@ namespace views::__adaptor using _Tp = remove_cvref_t<_Range>; if constexpr (__detail::__is_empty_view<_Tp>) return _Tp(); +#ifdef __cpp_lib_optional_range_support // >= C++26 + else if constexpr (__is_optional_v<_Tp> && view<_Tp>) + return __n ? _Tp() : std::forward<_Range>(__r); +#endif else if constexpr (random_access_range<_Tp> && sized_range<_Tp> && (std::__detail::__is_span<_Tp> @@ -2805,7 +2940,7 @@ namespace views::__adaptor && default_initializable<_Pred>) = default; - constexpr + constexpr explicit drop_while_view(_Vp __base, _Pred __pred) : _M_base(std::move(__base)), _M_pred(std::move(__pred)) { } @@ -2972,7 +3107,12 @@ namespace views::__adaptor } if constexpr (_S_ref_is_glvalue) - _M_inner.reset(); + { + if constexpr (forward_iterator<_Inner_iter>) + _M_inner = _Inner_iter(); + else + _M_inner.reset(); + } } static constexpr auto @@ -3012,6 +3152,24 @@ namespace views::__adaptor return *_M_parent->_M_outer; } + constexpr _Inner_iter& + _M_get_inner() noexcept + { + if constexpr (forward_iterator<_Inner_iter>) + return _M_inner; + else + return *_M_inner; + } + + constexpr const _Inner_iter& + _M_get_inner() const noexcept + { + if constexpr (forward_iterator<_Inner_iter>) + return _M_inner; + else + return *_M_inner; + } + constexpr _Iterator(_Parent* __parent, _Outer_iter __outer) requires forward_range<_Base> : _M_outer(std::move(__outer)), _M_parent(__parent) @@ -3023,8 +3181,11 @@ namespace views::__adaptor { _M_satisfy(); } [[no_unique_address]] - __detail::__maybe_present_t<forward_range<_Base>, _Outer_iter> _M_outer; - optional<_Inner_iter> _M_inner; + __detail::__maybe_present_t<forward_range<_Base>, _Outer_iter> _M_outer + = decltype(_M_outer)(); + __conditional_t<forward_iterator<_Inner_iter>, + _Inner_iter, optional<_Inner_iter>> _M_inner + = decltype(_M_inner)(); _Parent* _M_parent = nullptr; public: @@ -3048,7 +3209,7 @@ namespace views::__adaptor constexpr decltype(auto) operator*() const - { return **_M_inner; } + { return *_M_get_inner(); } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3500. join_view::iterator::operator->() is bogus @@ -3056,7 +3217,7 @@ namespace views::__adaptor operator->() const requires __detail::__has_arrow<_Inner_iter> && copyable<_Inner_iter> - { return *_M_inner; } + { return _M_get_inner(); } constexpr _Iterator& operator++() @@ -3067,7 +3228,7 @@ namespace views::__adaptor else return *_M_parent->_M_inner; }(); - if (++*_M_inner == ranges::end(__inner_range)) + if (++_M_get_inner() == ranges::end(__inner_range)) { ++_M_get_outer(); _M_satisfy(); @@ -3097,9 +3258,9 @@ namespace views::__adaptor { if (_M_outer == ranges::end(_M_parent->_M_base)) _M_inner = ranges::end(__detail::__as_lvalue(*--_M_outer)); - while (*_M_inner == ranges::begin(__detail::__as_lvalue(*_M_outer))) - *_M_inner = ranges::end(__detail::__as_lvalue(*--_M_outer)); - --*_M_inner; + while (_M_get_inner() == ranges::begin(__detail::__as_lvalue(*_M_outer))) + _M_get_inner() = ranges::end(__detail::__as_lvalue(*--_M_outer)); + --_M_get_inner(); return *this; } @@ -3126,14 +3287,14 @@ namespace views::__adaptor friend constexpr decltype(auto) iter_move(const _Iterator& __i) - noexcept(noexcept(ranges::iter_move(*__i._M_inner))) - { return ranges::iter_move(*__i._M_inner); } + noexcept(noexcept(ranges::iter_move(__i._M_get_inner()))) + { return ranges::iter_move(__i._M_get_inner()); } friend constexpr void iter_swap(const _Iterator& __x, const _Iterator& __y) - noexcept(noexcept(ranges::iter_swap(*__x._M_inner, *__y._M_inner))) + noexcept(noexcept(ranges::iter_swap(__x._M_get_inner(), __y._M_get_inner()))) requires indirectly_swappable<_Inner_iter> - { return ranges::iter_swap(*__x._M_inner, *__y._M_inner); } + { return ranges::iter_swap(__x._M_get_inner(), __y._M_get_inner()); } friend _Iterator<!_Const>; template<bool> friend struct _Sentinel; @@ -3377,7 +3538,8 @@ namespace views::__adaptor [[no_unique_address]] __detail::__maybe_present_t<forward_range<_Vp>, - iterator_t<_Base>> _M_current; + iterator_t<_Base>> _M_current + = decltype(_M_current)(); bool _M_trailing_empty = false; public: @@ -3642,7 +3804,7 @@ namespace views::__adaptor && default_initializable<_Pattern>) = default; - constexpr + constexpr explicit lazy_split_view(_Vp __base, _Pattern __pattern) : _M_base(std::move(__base)), _M_pattern(std::move(__pattern)) { } @@ -3650,7 +3812,7 @@ namespace views::__adaptor template<input_range _Range> requires constructible_from<_Vp, views::all_t<_Range>> && constructible_from<_Pattern, single_view<range_value_t<_Range>>> - constexpr + constexpr explicit lazy_split_view(_Range&& __r, range_value_t<_Range> __e) : _M_base(views::all(std::forward<_Range>(__r))), _M_pattern(views::single(std::move(__e))) @@ -3767,7 +3929,7 @@ namespace views::__adaptor && default_initializable<_Pattern>) = default; - constexpr + constexpr explicit split_view(_Vp __base, _Pattern __pattern) : _M_base(std::move(__base)), _M_pattern(std::move(__pattern)) { } @@ -3775,7 +3937,7 @@ namespace views::__adaptor template<forward_range _Range> requires constructible_from<_Vp, views::all_t<_Range>> && constructible_from<_Pattern, single_view<range_value_t<_Range>>> - constexpr + constexpr explicit split_view(_Range&& __r, range_value_t<_Range> __e) : _M_base(views::all(std::forward<_Range>(__r))), _M_pattern(views::single(std::move(__e))) @@ -4198,6 +4360,10 @@ namespace views::__adaptor using _Tp = remove_cvref_t<_Range>; if constexpr (__detail::__is_reverse_view<_Tp>) return std::forward<_Range>(__r).base(); +#ifdef __cpp_lib_optional_range_support // >= C++26 + else if constexpr (__is_optional_v<_Tp> && view<_Tp>) + return std::forward<_Range>(__r); +#endif else if constexpr (__detail::__is_reversible_subrange<_Tp>) { using _Iter = decltype(ranges::begin(__r).base()); @@ -5156,13 +5322,21 @@ namespace views::__adaptor class zip_transform_view<_Fp, _Vs...>::_Iterator : public __iter_cat<_Const> { using _Parent = __detail::__maybe_const_t<_Const, zip_transform_view>; + using _Fun_handle = __detail::__func_handle_t< + __detail::__maybe_const_t<_Const, _Fp>, + iterator_t<__detail::__maybe_const_t<_Const, _Vs>>...>; - _Parent* _M_parent = nullptr; + [[no_unique_address]] _Fun_handle _M_fun; __ziperator<_Const> _M_inner; constexpr + _Iterator(_Fun_handle __fun, __ziperator<_Const> __inner) + : _M_fun(__fun), _M_inner(std::move(__inner)) + { } + + constexpr _Iterator(_Parent& __parent, __ziperator<_Const> __inner) - : _M_parent(std::__addressof(__parent)), _M_inner(std::move(__inner)) + : _M_fun(*__parent._M_fun), _M_inner(std::move(__inner)) { } friend class zip_transform_view; @@ -5180,14 +5354,14 @@ namespace views::__adaptor constexpr _Iterator(_Iterator<!_Const> __i) requires _Const && convertible_to<__ziperator<false>, __ziperator<_Const>> - : _M_parent(__i._M_parent), _M_inner(std::move(__i._M_inner)) + : _M_fun(__i._M_fun), _M_inner(std::move(__i._M_inner)) { } constexpr decltype(auto) operator*() const { return std::apply([&](const auto&... __iters) -> decltype(auto) { - return std::__invoke(*_M_parent->_M_fun, *__iters...); + return _M_fun._M_call_deref(__iters...); }, _M_inner._M_current); } @@ -5243,7 +5417,7 @@ namespace views::__adaptor operator[](difference_type __n) const requires random_access_range<_Base<_Const>> { return std::apply([&]<typename... _Is>(const _Is&... __iters) -> decltype(auto) { - return std::__invoke(*_M_parent->_M_fun, __iters[iter_difference_t<_Is>(__n)]...); + return _M_fun._M_call_subscript(__n, __iters...); }, _M_inner._M_current); } @@ -5260,17 +5434,17 @@ namespace views::__adaptor friend constexpr _Iterator operator+(const _Iterator& __i, difference_type __n) requires random_access_range<_Base<_Const>> - { return _Iterator(*__i._M_parent, __i._M_inner + __n); } + { return _Iterator(__i._M_fun, __i._M_inner + __n); } friend constexpr _Iterator operator+(difference_type __n, const _Iterator& __i) requires random_access_range<_Base<_Const>> - { return _Iterator(*__i._M_parent, __i._M_inner + __n); } + { return _Iterator(__i._M_fun, __i._M_inner + __n); } friend constexpr _Iterator operator-(const _Iterator& __i, difference_type __n) requires random_access_range<_Base<_Const>> - { return _Iterator(*__i._M_parent, __i._M_inner - __n); } + { return _Iterator(__i._M_fun, __i._M_inner - __n); } friend constexpr difference_type operator-(const _Iterator& __x, const _Iterator& __y) @@ -5337,7 +5511,7 @@ namespace views::__adaptor requires move_constructible<decay_t<_Fp>> && regular_invocable<decay_t<_Fp>&> && is_object_v<decay_t<invoke_result_t<decay_t<_Fp>&>>> constexpr auto - operator() [[nodiscard]] (_Fp&& __f) const + operator() [[nodiscard]] (_Fp&&) const { return views::empty<decay_t<invoke_result_t<decay_t<_Fp>&>>>; } @@ -5439,7 +5613,7 @@ namespace views::__adaptor { // Yields tuple<_Tp, ..., _Tp> with _Nm elements. template<typename _Tp, size_t _Nm> - using __repeated_tuple = decltype(std::tuple_cat(std::declval<array<_Tp, _Nm>>())); + using __repeated_tuple = typename __make_tuple<array<_Tp, _Nm>>::__type; // For a functor F that is callable with N arguments, the expression // declval<__unarize<F, N>>(x) is equivalent to declval<F>(x, ..., x). @@ -5516,9 +5690,7 @@ namespace views::__adaptor public: using iterator_category = input_iterator_tag; using iterator_concept = decltype(_S_iter_concept()); - using value_type = conditional_t<_Nm == 2, - pair<range_value_t<_Base>, range_value_t<_Base>>, - __detail::__repeated_tuple<range_value_t<_Base>, _Nm>>; + using value_type = __detail::__repeated_tuple<range_value_t<_Base>, _Nm>; using difference_type = range_difference_t<_Base>; _Iterator() = default; @@ -5839,13 +6011,23 @@ namespace views::__adaptor { using _Parent = __detail::__maybe_const_t<_Const, adjacent_transform_view>; using _Base = __detail::__maybe_const_t<_Const, _Vp>; + using _Fun_handle = decltype([]<size_t... _Ids>(std::index_sequence<_Ids...>) { + return __detail::__func_handle_t< + __detail::__maybe_const_t<_Const, _Fp>, + iterator_t<__detail::__maybe_const_t<(_Ids, _Const), _Vp>>...>(); + }(make_index_sequence<_Nm>())); - _Parent* _M_parent = nullptr; + [[no_unique_address]] _Fun_handle _M_fun; _InnerIter<_Const> _M_inner; constexpr + _Iterator(_Fun_handle __fun, _InnerIter<_Const> __inner) + : _M_fun(__fun), _M_inner(std::move(__inner)) + { } + + constexpr _Iterator(_Parent& __parent, _InnerIter<_Const> __inner) - : _M_parent(std::__addressof(__parent)), _M_inner(std::move(__inner)) + : _M_fun(*__parent._M_fun), _M_inner(std::move(__inner)) { } static auto @@ -5886,14 +6068,14 @@ namespace views::__adaptor constexpr _Iterator(_Iterator<!_Const> __i) requires _Const && convertible_to<_InnerIter<false>, _InnerIter<_Const>> - : _M_parent(__i._M_parent), _M_inner(std::move(__i._M_inner)) + : _M_fun(__i._M_fun), _M_inner(std::move(__i._M_inner)) { } constexpr decltype(auto) operator*() const { return std::apply([&](const auto&... __iters) -> decltype(auto) { - return std::__invoke(*_M_parent->_M_fun, *__iters...); + return _M_fun._M_call_deref(__iters...); }, _M_inner._M_current); } @@ -5945,7 +6127,7 @@ namespace views::__adaptor operator[](difference_type __n) const requires random_access_range<_Base> { return std::apply([&](const auto&... __iters) -> decltype(auto) { - return std::__invoke(*_M_parent->_M_fun, __iters[__n]...); + return _M_fun._M_call_subscript(__n, __iters...); }, _M_inner._M_current); } @@ -5982,17 +6164,17 @@ namespace views::__adaptor friend constexpr _Iterator operator+(const _Iterator& __i, difference_type __n) requires random_access_range<_Base> - { return _Iterator(*__i._M_parent, __i._M_inner + __n); } + { return _Iterator(__i._M_fun, __i._M_inner + __n); } friend constexpr _Iterator operator+(difference_type __n, const _Iterator& __i) requires random_access_range<_Base> - { return _Iterator(*__i._M_parent, __i._M_inner + __n); } + { return _Iterator(__i._M_fun, __i._M_inner + __n); } friend constexpr _Iterator operator-(const _Iterator& __i, difference_type __n) requires random_access_range<_Base> - { return _Iterator(*__i._M_parent, __i._M_inner - __n); } + { return _Iterator(__i._M_fun, __i._M_inner - __n); } friend constexpr difference_type operator-(const _Iterator& __x, const _Iterator& __y) @@ -6599,7 +6781,7 @@ namespace views::__adaptor } friend constexpr difference_type - operator-(default_sentinel_t __y, const _Iterator& __x) + operator-(default_sentinel_t, const _Iterator& __x) requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>> { return __detail::__div_ceil(__x._M_end - __x._M_current, __x._M_n); } @@ -7288,15 +7470,15 @@ namespace views::__adaptor using iterator_category = decltype(_S_iter_cat()); }; - template<bool> struct _Iterator; - template<bool> struct _Sentinel; + template<bool> class _Iterator; + template<bool> class _Sentinel; public: join_with_view() requires (default_initializable<_Vp> && default_initializable<_Pattern>) = default; - constexpr + constexpr explicit join_with_view(_Vp __base, _Pattern __pattern) : _M_base(std::move(__base)), _M_pattern(std::move(__pattern)) { } @@ -7304,7 +7486,7 @@ namespace views::__adaptor template<input_range _Range> requires constructible_from<_Vp, views::all_t<_Range>> && constructible_from<_Pattern, single_view<range_value_t<_InnerRange>>> - constexpr + constexpr explicit join_with_view(_Range&& __r, range_value_t<_InnerRange> __e) : _M_base(views::all(std::forward<_Range>(__r))), _M_pattern(views::single(std::move(__e))) @@ -7401,7 +7583,8 @@ namespace views::__adaptor _Parent* _M_parent = nullptr; [[no_unique_address]] - __detail::__maybe_present_t<forward_range<_Base>, _OuterIter> _M_outer_it; + __detail::__maybe_present_t<forward_range<_Base>, _OuterIter> _M_outer_it + = decltype(_M_outer_it)(); variant<_PatternIter, _InnerIter> _M_inner_it; constexpr _OuterIter& @@ -7744,7 +7927,7 @@ namespace views::__adaptor __detail::__box<_Tp> _M_value; [[no_unique_address]] _Bound _M_bound = _Bound(); - struct _Iterator; + class _Iterator; template<typename _Range> friend constexpr auto @@ -8304,7 +8487,7 @@ namespace views::__adaptor } friend constexpr difference_type - operator-(default_sentinel_t __y, const _Iterator& __x) + operator-(default_sentinel_t, const _Iterator& __x) requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>> { return __detail::__div_ceil(__x._M_end - __x._M_current, __x._M_stride); } @@ -9355,6 +9538,10 @@ namespace views::__adaptor return views::all(std::forward<_Range>(__r)); else if constexpr (__detail::__is_empty_view<_Tp>) return views::empty<const element_type>; +#if __cpp_lib_optional >= 202506L && __cpp_lib_optional_range_support // >= C++26 + else if constexpr (__is_optional_ref_v<_Tp>) + return optional<const typename _Tp::value_type&>(__r); +#endif else if constexpr (std::__detail::__is_span<_Tp>) return span<const element_type, _Tp::extent>(std::forward<_Range>(__r)); else if constexpr (__detail::__is_constable_ref_view<_Tp>) @@ -9736,7 +9923,7 @@ namespace ranges end() requires (!(__detail::__simple_view<_Vs> && ...)) { constexpr auto __n = sizeof...(_Vs); - if constexpr ((semiregular<iterator_t<_Vs>> && ...) + if constexpr (__detail::__all_forward<false, _Vs...> && common_range<_Vs...[__n - 1]>) return _Iterator<false>(this, in_place_index<__n - 1>, ranges::end(std::get<__n - 1>(_M_views))); @@ -9748,7 +9935,7 @@ namespace ranges end() const requires (range<const _Vs> && ...) && __detail::__concatable<const _Vs...> { constexpr auto __n = sizeof...(_Vs); - if constexpr ((semiregular<iterator_t<const _Vs>> && ...) + if constexpr (__detail::__all_forward<true, _Vs...> && common_range<const _Vs...[__n - 1]>) return _Iterator<true>(this, in_place_index<__n - 1>, ranges::end(std::get<__n - 1>(_M_views))); diff --git a/libstdc++-v3/include/std/regex b/libstdc++-v3/include/std/regex index 0223066..9121d26 100644 --- a/libstdc++-v3/include/std/regex +++ b/libstdc++-v3/include/std/regex @@ -41,7 +41,6 @@ #include <bitset> #include <locale> -#include <sstream> #include <stack> #include <stdexcept> #include <string> diff --git a/libstdc++-v3/include/std/semaphore b/libstdc++-v3/include/std/semaphore index bec5ac3..18d0407 100644 --- a/libstdc++-v3/include/std/semaphore +++ b/libstdc++-v3/include/std/semaphore @@ -35,29 +35,28 @@ #include <bits/requires_hosted.h> // concurrency -#if __cplusplus > 201703L -#include <bits/semaphore_base.h> - #define __glibcxx_want_semaphore #include <bits/version.h> -#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && (atomic_wait || posix_sem) +#ifdef __cpp_lib_semaphore // C++ >= 20 && hosted && atomic_wait +#include <bits/semaphore_base.h> + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - template<ptrdiff_t __least_max_value = __semaphore_impl::_S_max> + template<ptrdiff_t __least_max_value = _Semaphore_impl<2>::_S_max> class counting_semaphore { static_assert(__least_max_value >= 0); - static_assert(__least_max_value <= __semaphore_impl::_S_max); - __semaphore_impl _M_sem; + _Semaphore_impl<__least_max_value> _M_sem; public: - explicit counting_semaphore(ptrdiff_t __desired) noexcept - : _M_sem(__desired) - { } + constexpr explicit + counting_semaphore(ptrdiff_t __desired) noexcept + : _M_sem(__desired) + { __glibcxx_assert(__desired >= 0 && __desired <= max()); } ~counting_semaphore() = default; @@ -69,8 +68,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __least_max_value; } void - release(ptrdiff_t __update = 1) noexcept(noexcept(_M_sem._M_release(1))) - { _M_sem._M_release(__update); } + release(ptrdiff_t __update = 1) noexcept + { + [[maybe_unused]] ptrdiff_t __old = _M_sem._M_release(__update); + __glibcxx_assert(__update >= 0 && __update <= max() - __old); + } void acquire() noexcept(noexcept(_M_sem._M_acquire())) @@ -91,10 +93,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return _M_sem._M_try_acquire_until(__atime); } }; + /** @brief A binary semaphore + * + * @since C++20 + */ using binary_semaphore = std::counting_semaphore<1>; _GLIBCXX_END_NAMESPACE_VERSION } // namespace -#endif // cpp_lib_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE #endif // __cpp_lib_semaphore #endif // _GLIBCXX_SEMAPHORE diff --git a/libstdc++-v3/include/std/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/shared_mutex b/libstdc++-v3/include/std/shared_mutex index 94c8532..92f6227 100644 --- a/libstdc++-v3/include/std/shared_mutex +++ b/libstdc++-v3/include/std/shared_mutex @@ -208,10 +208,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION try_lock() { int __ret = __glibcxx_rwlock_trywrlock(&_M_rwlock); - if (__ret == EBUSY) return false; - // Errors not handled: EINVAL + if (__ret == 0) + return true; + if (__ret == EBUSY) + return false; + // Errors not handled: EINVAL, EDEADLK __glibcxx_assert(__ret == 0); - return true; + // try_lock() is not permitted to throw + return false; } void @@ -520,23 +524,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION try_lock_until(const chrono::time_point<chrono::system_clock, _Duration>& __atime) { - auto __s = chrono::time_point_cast<chrono::seconds>(__atime); - auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); - - __gthread_time_t __ts = - { - static_cast<std::time_t>(__s.time_since_epoch().count()), - static_cast<long>(__ns.count()) - }; - + struct timespec __ts = chrono::__to_timeout_timespec(__atime); int __ret = __glibcxx_rwlock_timedwrlock(&_M_rwlock, &__ts); - // On self-deadlock, we just fail to acquire the lock. Technically, - // the program violated the precondition. - if (__ret == ETIMEDOUT || __ret == EDEADLK) + if (__ret == 0) + return true; + if (__ret == ETIMEDOUT) return false; - // Errors not handled: EINVAL + // Errors not handled: EINVAL, EDEADLK __glibcxx_assert(__ret == 0); - return true; + return false; } #ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK @@ -546,24 +542,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION try_lock_until(const chrono::time_point<chrono::steady_clock, _Duration>& __atime) { - auto __s = chrono::time_point_cast<chrono::seconds>(__atime); - auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); - - __gthread_time_t __ts = - { - static_cast<std::time_t>(__s.time_since_epoch().count()), - static_cast<long>(__ns.count()) - }; - + struct timespec __ts = chrono::__to_timeout_timespec(__atime); int __ret = pthread_rwlock_clockwrlock(&_M_rwlock, CLOCK_MONOTONIC, &__ts); - // On self-deadlock, we just fail to acquire the lock. Technically, - // the program violated the precondition. - if (__ret == ETIMEDOUT || __ret == EDEADLK) + if (__ret == 0) + return true; + if (__ret == ETIMEDOUT) return false; - // Errors not handled: EINVAL + // Errors not handled: EINVAL, EDEADLK __glibcxx_assert(__ret == 0); - return true; + return false; } #endif @@ -596,14 +584,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION try_lock_shared_until(const chrono::time_point<chrono::system_clock, _Duration>& __atime) { - auto __s = chrono::time_point_cast<chrono::seconds>(__atime); - auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); - - __gthread_time_t __ts = - { - static_cast<std::time_t>(__s.time_since_epoch().count()), - static_cast<long>(__ns.count()) - }; + struct timespec __ts = chrono::__to_timeout_timespec(__atime); int __ret; // Unlike for lock(), we are not allowed to throw an exception so if @@ -615,18 +596,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // acquire the lock even if it would be logically free; however, this // is allowed by the standard, and we made a "strong effort" // (see C++14 30.4.1.4p26). - // For cases where the implementation detects a deadlock we - // intentionally block and timeout so that an early return isn't - // mistaken for a spurious failure, which might help users realise - // there is a deadlock. do __ret = __glibcxx_rwlock_timedrdlock(&_M_rwlock, &__ts); - while (__ret == EAGAIN || __ret == EDEADLK); + while (__ret == EAGAIN); + if (__ret == 0) + return true; if (__ret == ETIMEDOUT) return false; - // Errors not handled: EINVAL + // Errors not handled: EINVAL, EDEADLK __glibcxx_assert(__ret == 0); - return true; + return false; } #ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK @@ -636,24 +615,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION try_lock_shared_until(const chrono::time_point<chrono::steady_clock, _Duration>& __atime) { - auto __s = chrono::time_point_cast<chrono::seconds>(__atime); - auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); - - __gthread_time_t __ts = - { - static_cast<std::time_t>(__s.time_since_epoch().count()), - static_cast<long>(__ns.count()) - }; - + struct timespec __ts = chrono::__to_timeout_timespec(__atime); int __ret = pthread_rwlock_clockrdlock(&_M_rwlock, CLOCK_MONOTONIC, &__ts); - // On self-deadlock, we just fail to acquire the lock. Technically, - // the program violated the precondition. - if (__ret == ETIMEDOUT || __ret == EDEADLK) + // On self-deadlock, if _GLIBCXX_ASSERTIONS is not defined, we just + // fail to acquire the lock. Technically, the program violated the + // precondition. + if (__ret == 0) + return true; + if (__ret == ETIMEDOUT) return false; - // Errors not handled: EINVAL + // Errors not handled: EINVAL, EDEADLK __glibcxx_assert(__ret == 0); - return true; + return false; } #endif diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 49ab910..5808911 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -376,7 +376,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else static_assert(_Count <= extent); using _Sp = span<element_type, _Count>; - return _Sp{ _SizedPtr{this->data()} }; + return _Sp(_SizedPtr{this->data()}); } [[nodiscard]] @@ -384,7 +384,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION first(size_type __count) const noexcept { __glibcxx_assert(__count <= size()); - return { this->data(), __count }; + return span<element_type>(this->data(), __count); } template<size_t _Count> @@ -397,7 +397,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else static_assert(_Count <= extent); using _Sp = span<element_type, _Count>; - return _Sp{ _SizedPtr{this->data() + (this->size() - _Count)} }; + return _Sp(_SizedPtr{this->data() + (this->size() - _Count)}); } [[nodiscard]] @@ -405,7 +405,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION last(size_type __count) const noexcept { __glibcxx_assert(__count <= size()); - return { this->data() + (this->size() - __count), __count }; + return span<element_type>(this->data() + (this->size() - __count), + __count); } template<size_t _Offset, size_t _Count = dynamic_extent> @@ -424,7 +425,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Sp = span<element_type, _S_subspan_extent<_Offset, _Count>()>; if constexpr (_Count == dynamic_extent) - return _Sp{ this->data() + _Offset, this->size() - _Offset }; + return _Sp(this->data() + _Offset, this->size() - _Offset); else { if constexpr (_Extent == dynamic_extent) @@ -437,7 +438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(_Count <= extent); static_assert(_Count <= (extent - _Offset)); } - return _Sp{ _SizedPtr{this->data() + _Offset} }; + return _Sp(_SizedPtr{this->data() + _Offset}); } } @@ -454,7 +455,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __glibcxx_assert(__count <= size()); __glibcxx_assert(__offset + __count <= size()); } - return {this->data() + __offset, __count}; + return span<element_type>(this->data() + __offset, __count); } private: @@ -476,6 +477,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; // deduction guides + namespace __detail + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4351. integral-constant-like needs more remove_cvref_t + template<typename _Tp> + concept __integral_constant_like = + is_integral_v<remove_cvref_t<decltype(_Tp::value)>> + && !is_same_v<bool, remove_cvref_t<decltype(_Tp::value)>> + && convertible_to<_Tp, decltype(_Tp::value)> + && equality_comparable_with<_Tp, decltype(_Tp::value)> + && bool_constant<_Tp() == _Tp::value>::value + && bool_constant<static_cast<decltype(_Tp::value)>(_Tp()) == _Tp::value> + ::value; + + template<typename _Tp> + constexpr size_t __maybe_static_ext = dynamic_extent; + + template<__integral_constant_like _Tp> + constexpr size_t __maybe_static_ext<_Tp> = {_Tp::value}; + } template<typename _Type, size_t _ArrayExtent> span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>; @@ -489,7 +510,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<contiguous_iterator _Iter, typename _End> span(_Iter, _End) - -> span<remove_reference_t<iter_reference_t<_Iter>>>; + -> span<remove_reference_t<iter_reference_t<_Iter>>, + __detail::__maybe_static_ext<_End>>; template<ranges::contiguous_range _Range> span(_Range &&) diff --git a/libstdc++-v3/include/std/spanstream b/libstdc++-v3/include/std/spanstream index 23a340a..fbb40ff 100644 --- a/libstdc++-v3/include/std/spanstream +++ b/libstdc++-v3/include/std/spanstream @@ -152,7 +152,7 @@ template<typename _CharT, typename _Traits> if (__way == ios_base::beg) { - if (0 <= __off && __off <= _M_buf.size()) + if (0 <= __off && (size_t)__off <= _M_buf.size()) { if (__which & ios_base::in) this->setg(this->eback(), this->eback() + __off, this->egptr()); @@ -188,7 +188,7 @@ template<typename _CharT, typename _Traits> if (__builtin_add_overflow(__base, __off, &__off)) [[unlikely]] return __ret; - if (__off < 0 || __off > _M_buf.size()) [[unlikely]] + if (__off < 0 || (size_t)__off > _M_buf.size()) [[unlikely]] return __ret; if (__which & ios_base::in) diff --git a/libstdc++-v3/include/std/sstream b/libstdc++-v3/include/std/sstream index ad0c16a..b1b4126 100644 --- a/libstdc++-v3/include/std/sstream +++ b/libstdc++-v3/include/std/sstream @@ -41,8 +41,16 @@ #include <istream> #include <ostream> + #include <bits/alloc_traits.h> // allocator_traits, __allocator_like +#define __glibcxx_want_sstream_from_string_view +#include <bits/version.h> + +#ifdef __cpp_lib_sstream_from_string_view +# include <string_view> +#endif + #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI # define _GLIBCXX_LVAL_REF_QUAL & # define _GLIBCXX_SSTREAM_ALWAYS_INLINE @@ -52,8 +60,6 @@ # define _GLIBCXX_SSTREAM_ALWAYS_INLINE [[__gnu__::__always_inline__]] #endif - - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -159,6 +165,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer explicit basic_stringbuf(const allocator_type& __a) : basic_stringbuf(ios_base::in | std::ios_base::out, __a) @@ -197,7 +204,36 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 | ios_base::out) : basic_stringbuf(__s, __mode, allocator_type{}) { } +#endif +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + explicit + basic_stringbuf(const _Tp& __t, + ios_base::openmode __mode = ios_base::in | ios_base::out) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_stringbuf(__t, __mode, allocator_type{}) + { } + + template<typename _Tp> + basic_stringbuf(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_stringbuf(__t, ios_base::in | ios_base::out, __a) + { } + + template<typename _Tp> + basic_stringbuf(const _Tp& __t, ios_base::openmode __mode, + const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : _M_string(__t, __a) + { _M_stringbuf_init(__mode); } +#endif // C++26 + +#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a) : basic_stringbuf(std::move(__rhs), __a, __xfer_bufptrs(__rhs, this)) { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0); } @@ -262,6 +298,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -317,6 +354,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -335,6 +373,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } #endif +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + { + basic_string_view<_CharT, _Traits> __sv{__t}; + _M_string = __sv; + _M_stringbuf_init(_M_mode); + } +#endif // C++26 + protected: // Common initialization code goes here. void @@ -521,6 +572,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer + // The move constructor initializes an __xfer_bufptrs temporary then // delegates to this constructor to performs moves during its lifetime. basic_stringbuf(basic_stringbuf&& __rhs, const allocator_type& __a, @@ -584,7 +637,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ basic_istringstream() : __istream_type(), _M_stringbuf(ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an empty string buffer. @@ -601,7 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_istringstream(ios_base::openmode __mode) : __istream_type(), _M_stringbuf(__mode | ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an existing string buffer. @@ -620,7 +673,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_istringstream(const __string_type& __str, ios_base::openmode __mode = ios_base::in) : __istream_type(), _M_stringbuf(__str, __mode | ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief The destructor does nothing. @@ -637,9 +690,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_istringstream(basic_istringstream&& __rhs) : __istream_type(std::move(__rhs)), _M_stringbuf(std::move(__rhs._M_stringbuf)) - { __istream_type::set_rdbuf(&_M_stringbuf); } + { __istream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_istringstream(ios_base::openmode __mode, const allocator_type& __a) : __istream_type(), _M_stringbuf(__mode | ios_base::in, __a) { this->init(std::__addressof(_M_stringbuf)); } @@ -671,6 +725,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #endif // C++20 +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + explicit + basic_istringstream(const _Tp& __t, + ios_base::openmode __mode = ios_base::in) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_istringstream(__t, __mode, allocator_type{}) + { } + + template <typename _Tp> + basic_istringstream(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_istringstream(__t, ios_base::in, __a) + { } + + template <typename _Tp> + basic_istringstream(const _Tp& __t, ios_base::openmode __mode, + const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : __istream_type(), _M_stringbuf(__t, __mode | ios_base::in, __a) + { this->init(std::__addressof(_M_stringbuf)); } +#endif // C++26 + // 27.8.3.2 Assign and swap: basic_istringstream& @@ -702,7 +782,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NODISCARD __stringbuf_type* rdbuf() const - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } + { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } /** * @brief Copying out the string buffer. @@ -716,6 +796,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -747,6 +828,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -758,6 +840,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 str(__string_type&& __s) { _M_stringbuf.str(std::move(__s)); } #endif + +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + { _M_stringbuf.str(__t); } +#endif // C++26 }; @@ -812,7 +903,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ basic_ostringstream() : __ostream_type(), _M_stringbuf(ios_base::out) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an empty string buffer. @@ -829,7 +920,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_ostringstream(ios_base::openmode __mode) : __ostream_type(), _M_stringbuf(__mode | ios_base::out) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an existing string buffer. @@ -848,7 +939,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_ostringstream(const __string_type& __str, ios_base::openmode __mode = ios_base::out) : __ostream_type(), _M_stringbuf(__str, __mode | ios_base::out) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief The destructor does nothing. @@ -865,9 +956,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_ostringstream(basic_ostringstream&& __rhs) : __ostream_type(std::move(__rhs)), _M_stringbuf(std::move(__rhs._M_stringbuf)) - { __ostream_type::set_rdbuf(&_M_stringbuf); } + { __ostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_ostringstream(ios_base::openmode __mode, const allocator_type& __a) : __ostream_type(), _M_stringbuf(__mode | ios_base::out, __a) { this->init(std::__addressof(_M_stringbuf)); } @@ -899,6 +991,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #endif // C++20 +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + explicit + basic_ostringstream( + const _Tp& __t, ios_base::openmode __mode = ios_base::out) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_ostringstream(__t, __mode, allocator_type{}) + { } + + template <typename _Tp> + basic_ostringstream(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_ostringstream(__t, ios_base::out, __a) + { } + + template <typename _Tp> + basic_ostringstream(const _Tp& __t, ios_base::openmode __mode, + const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : __ostream_type(), _M_stringbuf(__t, __mode | ios_base::out, __a) + { this->init(std::__addressof(_M_stringbuf)); } +#endif // C++26 + // 27.8.3.2 Assign and swap: basic_ostringstream& @@ -930,7 +1048,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NODISCARD __stringbuf_type* rdbuf() const - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } + { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } /** * @brief Copying out the string buffer. @@ -944,6 +1062,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -975,6 +1094,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -986,6 +1106,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 str(__string_type&& __s) { _M_stringbuf.str(std::move(__s)); } #endif + +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + { _M_stringbuf.str(__t); } +#endif // C++26 }; @@ -1040,7 +1169,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ basic_stringstream() : __iostream_type(), _M_stringbuf(ios_base::out | ios_base::in) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an empty string buffer. @@ -1055,7 +1184,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_stringstream(ios_base::openmode __m) : __iostream_type(), _M_stringbuf(__m) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief Starts with an existing string buffer. @@ -1072,7 +1201,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_stringstream(const __string_type& __str, ios_base::openmode __m = ios_base::out | ios_base::in) : __iostream_type(), _M_stringbuf(__str, __m) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } /** * @brief The destructor does nothing. @@ -1089,12 +1218,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_stringstream(basic_stringstream&& __rhs) : __iostream_type(std::move(__rhs)), _M_stringbuf(std::move(__rhs._M_stringbuf)) - { __iostream_type::set_rdbuf(&_M_stringbuf); } + { __iostream_type::set_rdbuf(std::__addressof(_M_stringbuf)); } #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI + // P0408 Efficient access to basic_stringbuf buffer basic_stringstream(ios_base::openmode __mode, const allocator_type& __a) : __iostream_type(), _M_stringbuf(__mode, __a) - { this->init(&_M_stringbuf); } + { this->init(std::__addressof(_M_stringbuf)); } explicit basic_stringstream(__string_type&& __str, @@ -1125,6 +1255,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { } #endif // C++20 +#ifdef __cpp_lib_sstream_from_string_view + template <typename _Tp> + explicit + basic_stringstream(const _Tp& __t, + ios_base::openmode __mode = ios_base::in | ios_base::out) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_stringstream(__t, __mode, allocator_type{}) + { } + + template <typename _Tp> + basic_stringstream(const _Tp& __t, const allocator_type& __a) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + : basic_stringstream(__t, ios_base::in | ios_base::out, __a) + { } + + template <typename _Tp> + basic_stringstream(const _Tp& __t, ios_base::openmode __mode, + const allocator_type& __a) + requires (is_convertible_v<const _Tp&, basic_string_view<_CharT, _Traits>>) + : __iostream_type(), _M_stringbuf(__t, __mode, __a) + { this->init(std::__addressof(_M_stringbuf)); } +#endif // C++26 + // 27.8.3.2 Assign and swap: basic_stringstream& @@ -1156,7 +1311,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NODISCARD __stringbuf_type* rdbuf() const - { return const_cast<__stringbuf_type*>(&_M_stringbuf); } + { return const_cast<__stringbuf_type*>(std::__addressof(_M_stringbuf)); } /** * @brief Copying out the string buffer. @@ -1170,6 +1325,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L #if _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> _GLIBCXX_NODISCARD basic_string<_CharT, _Traits, _SAlloc> @@ -1201,6 +1357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI #if __cpp_concepts + // P0407 Allocator-aware basic_streambuf template<__allocator_like _SAlloc> requires (!is_same_v<_SAlloc, _Alloc>) void @@ -1212,6 +1369,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 str(__string_type&& __s) { _M_stringbuf.str(std::move(__s)); } #endif + +#ifdef __cpp_lib_sstream_from_string_view + template<typename _Tp> + void + str(const _Tp& __t) + requires (is_convertible_v<const _Tp&, + basic_string_view<_CharT, _Traits>>) + { _M_stringbuf.str(__t); } +#endif // C++26 }; #if __cplusplus >= 201103L diff --git a/libstdc++-v3/include/std/stack b/libstdc++-v3/include/std/stack index 2f7951a..507b974 100644 --- a/libstdc++-v3/include/std/stack +++ b/libstdc++-v3/include/std/stack @@ -61,10 +61,61 @@ #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; + }; + +#if __glibcxx_print >= 202406L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4398. enable_nonlocking_formatter_optimization should be disabled for container adaptors + template<typename _Tp, typename _Container> + constexpr bool + enable_nonlocking_formatter_optimization<stack<_Tp, _Container>> = false; +#endif +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // __glibcxx_format_ranges + #endif /* _GLIBCXX_STACK */ diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace index 4911222..587a163 100644 --- a/libstdc++-v3/include/std/stacktrace +++ b/libstdc++-v3/include/std/stacktrace @@ -208,6 +208,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (_S_current(__cb, std::__addressof(__ret))) __ret._M_clear(); + else + __ret._M_trim(); } return __ret; } @@ -224,6 +226,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (_S_current(__cb, std::__addressof(__ret), __skip)) __ret._M_clear(); + else + __ret._M_trim(); } return __ret; @@ -260,6 +264,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } } + else + __ret._M_trim(); } return __ret; } @@ -651,6 +657,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + void + _M_trim() noexcept + { + // libbacktrace adds an invalid -1UL entry at the end, remove it. + if (!empty() && !end()[-1]) + _M_impl._M_resize(size() - 1, _M_alloc); + } + [[no_unique_address]] allocator_type _M_alloc{}; _Impl _M_impl{}; @@ -669,13 +683,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline ostream& operator<<(ostream& __os, const stacktrace_entry& __f) { + if (!__f) [[unlikely]] + return __os << "<unknown>"; + string __desc, __file; int __line; - if (__f._M_get_info(&__desc, &__file, &__line)) + if (__f._M_get_info(&__desc, &__file, &__line)) [[likely]] { - __os.width(4); - __os << __desc << " at " << __file << ':' << __line; + __os << ' '; + if (__desc.empty()) [[unlikely]] + __os << "<unknown>"; + else + __os << __desc; + if (!__file.empty()) [[likely]] + __os << " at " << __file << ':' << __line; } + + struct _Flag_guard // Set and restore hex format + { + _Flag_guard(ios& __s) : _M_ios(__s) { } + ~_Flag_guard() { _M_ios.setf(_M_f); } + + ios& _M_ios; + ios::fmtflags _M_f = _M_ios.setf(ios::hex, ios::basefield); + }; + _Flag_guard __g(__os); + __os << " [0x" << __f.native_handle() << ']'; return __os; } @@ -683,7 +716,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline ostream& operator<<(ostream& __os, const basic_stacktrace<_Allocator>& __st) { - for (stacktrace::size_type __i = 0; __i < __st.size(); ++__i) + using size_type = typename basic_stacktrace<_Allocator>::size_type; + for (size_type __i = 0, __size = __st.size(); __i < __size; ++__i) { __os.width(4); __os << __i << "# " << __st[__i] << '\n'; @@ -765,6 +799,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __format::_Spec<char> _M_spec; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization<stacktrace_entry> = true; +#endif + template<typename _Allocator> class formatter<basic_stacktrace<_Allocator>> { @@ -790,6 +830,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; +#if __glibcxx_print >= 202406L + template<typename _Allocator> + constexpr bool + enable_nonlocking_formatter_optimization<basic_stacktrace<_Allocator>> = true; +#endif + namespace pmr { using stacktrace diff --git a/libstdc++-v3/include/std/stop_token b/libstdc++-v3/include/std/stop_token index 1225b3a..b593daf 100644 --- a/libstdc++-v3/include/std/stop_token +++ b/libstdc++-v3/include/std/stop_token @@ -34,8 +34,7 @@ #define __glibcxx_want_jthread #include <bits/version.h> -#if __cplusplus > 201703L - +#ifdef __glibcxx_jthread // C++ >= 20 #include <atomic> #include <bits/std_thread.h> @@ -649,7 +648,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Callback> stop_callback(stop_token, _Callback) -> stop_callback<_Callback>; + /// @cond undocumented + namespace __detail::__variant + { + template<typename> struct _Never_valueless_alt; // see <variant> + + // Provide the strong exception-safety guarantee when emplacing a + // stop_token or stop_source into a variant. + template<> + struct _Never_valueless_alt<std::stop_token> + : true_type + { }; + + template<> + struct _Never_valueless_alt<std::stop_source> + : true_type + { }; + } // namespace __detail::__variant + /// @endcond + _GLIBCXX_END_NAMESPACE_VERSION -} // namespace -#endif // __cplusplus > 201703L +} // namespace std +#endif // __glibcxx_jthread #endif // _GLIBCXX_STOP_TOKEN diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string index 6211da9..918b415 100644 --- a/libstdc++-v3/include/std/string +++ b/libstdc++-v3/include/std/string @@ -51,7 +51,6 @@ #include <bits/stl_function.h> // For less #include <ext/numeric_traits.h> #include <bits/stl_algobase.h> -#include <bits/refwrap.h> #include <bits/range_access.h> #include <bits/basic_string.h> #include <bits/basic_string.tcc> @@ -60,9 +59,11 @@ #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 +#define __glibcxx_want_string_subview #define __glibcxx_want_string_udls #define __glibcxx_want_to_string #include <bits/version.h> @@ -95,33 +96,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _CharT, typename _Traits, typename _Alloc, typename _Predicate> - _GLIBCXX20_CONSTEXPR - inline typename basic_string<_CharT, _Traits, _Alloc>::size_type + constexpr typename basic_string<_CharT, _Traits, _Alloc>::size_type erase_if(basic_string<_CharT, _Traits, _Alloc>& __cont, _Predicate __pred) { using namespace __gnu_cxx; const auto __osz = __cont.size(); const auto __end = __cont.end(); auto __removed = std::__remove_if(__cont.begin(), __end, - __ops::__pred_iter(std::ref(__pred))); + std::move(__pred)); __cont.erase(__removed, __end); return __osz - __cont.size(); } template<typename _CharT, typename _Traits, typename _Alloc, typename _Up _GLIBCXX26_DEF_VAL_T(_CharT)> - _GLIBCXX20_CONSTEXPR - inline typename basic_string<_CharT, _Traits, _Alloc>::size_type + constexpr typename basic_string<_CharT, _Traits, _Alloc>::size_type erase(basic_string<_CharT, _Traits, _Alloc>& __cont, const _Up& __value) - { - using namespace __gnu_cxx; - const auto __osz = __cont.size(); - const auto __end = __cont.end(); - auto __removed = std::__remove_if(__cont.begin(), __end, - __ops::__iter_equals_val(__value)); - __cont.erase(__removed, __end); - return __osz - __cont.size(); - } + { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); } + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cpp_lib_erase_if diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view index 842f6ad..b226544 100644 --- a/libstdc++-v3/include/std/string_view +++ b/libstdc++-v3/include/std/string_view @@ -40,9 +40,10 @@ #define __glibcxx_want_constexpr_char_traits #define __glibcxx_want_constexpr_string_view #define __glibcxx_want_freestanding_string_view -#define __glibcxx_want_string_view #define __glibcxx_want_starts_ends_with #define __glibcxx_want_string_contains +#define __glibcxx_want_string_subview +#define __glibcxx_want_string_view #include <bits/version.h> #if __cplusplus >= 201703L @@ -342,6 +343,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return basic_string_view{_M_str + __pos, __rlen}; } +#ifdef __glibcxx_string_subview // >= C++26 + [[nodiscard]] + constexpr basic_string_view + subview(size_type __pos = 0, size_type __n = npos) const + { return substr(__pos, __n); } +#endif + [[nodiscard]] constexpr int compare(basic_string_view __str) const noexcept diff --git a/libstdc++-v3/include/std/syncstream b/libstdc++-v3/include/std/syncstream index e2b5a19..1e17597 100644 --- a/libstdc++-v3/include/std/syncstream +++ b/libstdc++-v3/include/std/syncstream @@ -46,7 +46,6 @@ #include <bits/alloc_traits.h> #include <bits/allocator.h> #include <bits/functexcept.h> -#include <bits/functional_hash.h> #include <bits/std_mutex.h> namespace std _GLIBCXX_VISIBILITY(default) @@ -199,11 +198,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __mutex { #if _GLIBCXX_HAS_GTHREADS - mutex* _M_mtx; + mutex* _M_mtx = nullptr; - __mutex(void* __t) - : _M_mtx(__t ? &_S_get_mutex(__t) : nullptr) - { } + __mutex(void* __t) // __t is the underlying sbuf, as hash seed. + { + extern mutex& __syncbuf_get_mutex(void*); // in src/c++20/syncbuf.cc + if (__t) _M_mtx = &__syncbuf_get_mutex(__t); + } void swap(__mutex& __other) noexcept @@ -220,17 +221,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { _M_mtx->unlock(); } - - // FIXME: This should be put in the .so - static mutex& - _S_get_mutex(void* __t) - { - const unsigned char __mask = 0xf; - static mutex __m[__mask + 1]; - - auto __key = _Hash_impl::hash(__t) & __mask; - return __m[__key]; - } #else __mutex(void*) { } void swap(__mutex&&) noexcept { } diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index d2f91ad..ccab1e4 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -294,10 +294,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION stop_source _M_stop_source; thread _M_thread; }; + + /// @cond undocumented + namespace __detail::__variant + { + template<typename> struct _Never_valueless_alt; // see <variant> + + // Provide the strong exception-safety guarantee when emplacing a + // jthread into a variant. + template<> + struct _Never_valueless_alt<std::jthread> + : true_type + { }; + } // namespace __detail::__variant + /// @endcond #endif // __cpp_lib_jthread #ifdef __cpp_lib_formatters // C++ >= 23 - template<typename _CharT> + // We deviate from the standard, that does not put requirements + // on _CharT here. + template<__format::__char _CharT> requires is_pointer_v<thread::native_handle_type> || is_integral_v<thread::native_handle_type> class formatter<thread::id, _CharT> @@ -307,6 +323,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION parse(basic_format_parse_context<_CharT>& __pc) { __format::_Spec<_CharT> __spec{}; + __spec._M_align = __format::_Align_right; const auto __last = __pc.end(); auto __first = __pc.begin(); @@ -334,41 +351,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__finished()) return __first; - __throw_format_error("format error: invalid format-spec for " - "std::thread::id"); + std::__throw_format_error("format error: invalid format-spec for " + "std::thread::id"); } template<typename _Out> typename basic_format_context<_Out, _CharT>::iterator format(thread::id __id, basic_format_context<_Out, _CharT>& __fc) const { - basic_string_view<_CharT> __sv; - if constexpr (is_same_v<_CharT, char>) - __sv = "{}thread::id of a non-executing thread"; - else - __sv = L"{}thread::id of a non-executing thread"; - basic_string<_CharT> __str; + if (__id == thread::id()) - __sv.remove_prefix(2); - else { - using _FmtStr = __format::_Runtime_format_string<_CharT>; - // Convert non-void pointers to const void* for formatted output. - using __output_type - = __conditional_t<is_pointer_v<thread::native_handle_type>, - const void*, - thread::native_handle_type>; - auto __o = static_cast<__output_type>(__id._M_thread); - __sv = __str = std::format(_FmtStr(__sv.substr(0, 2)), __o); + const _CharT* __msg; + if constexpr (is_same_v<_CharT, char>) + __msg = "thread::id of a non-executing thread"; + else + __msg = L"thread::id of a non-executing thread"; + + __format::__formatter_str<_CharT> __formatter(_M_spec); + return __formatter.format(__msg, __fc); } - return __format::__write_padded_as_spec(__sv, __sv.size(), - __fc, _M_spec, - __format::_Align_right); + + using _HandleFormatter + = __conditional_t<is_pointer_v<thread::native_handle_type>, + __format::__formatter_ptr<_CharT>, + __format::__formatter_int<_CharT>>; + + _HandleFormatter __formatter(_M_spec); + return __formatter.format(__id._M_thread, __fc); } private: __format::_Spec<_CharT> _M_spec; }; + +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization<thread::id> = true; +#endif + #endif // __cpp_lib_formatters /// @} group threads diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 2e69af1..d4db125 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -1984,14 +1984,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION class tuple<> { public: + // We need the default since we're going to define no-op + // allocator constructors. + tuple() = default; + // Defaulted copy operations to maintain trivial copyability. + // and support non-const assignment expressions. + tuple(const tuple&) = default; + tuple& operator=(const tuple&) = default; + _GLIBCXX20_CONSTEXPR void swap(tuple&) noexcept { /* no-op */ } + #if __cpp_lib_ranges_zip // >= C++23 - constexpr void swap(const tuple&) const noexcept { /* no-op */ } + template<same_as<tuple> _Tuple = tuple> + constexpr const tuple& + operator=(const _Tuple&) const noexcept + { return *this; } + + constexpr void swap(const tuple&) const noexcept + { /* no-op */ } #endif - // We need the default since we're going to define no-op - // allocator constructors. - tuple() = default; + // No-op allocator constructors. template<typename _Alloc> _GLIBCXX20_CONSTEXPR @@ -1999,6 +2012,48 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Alloc> _GLIBCXX20_CONSTEXPR tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept { } + +#if __cpp_lib_tuple_like // >= C++23 + template<__tuple_like _UTuple> + requires (!is_same_v<remove_cvref_t<_UTuple>, tuple>) + && (!is_same_v<remove_cvref_t<_UTuple>, allocator_arg_t>) + && (tuple_size_v<remove_cvref_t<_UTuple>> == 0) + constexpr + tuple(_UTuple&&) noexcept { } + + template<typename _Alloc, __tuple_like _UTuple> + requires (!is_same_v<remove_cvref_t<_UTuple>, tuple>) + && (tuple_size_v<remove_cvref_t<_UTuple>> == 0) + constexpr + tuple(allocator_arg_t, const _Alloc&, _UTuple&&) noexcept { } + + template<__tuple_like _UTuple> + requires (!is_same_v<remove_cvref_t<_UTuple>, tuple>) + && (tuple_size_v<remove_cvref_t<_UTuple>> == 0) + constexpr tuple& + operator=(_UTuple&&) noexcept + { return *this; } + + template<__tuple_like _UTuple> + requires (!is_same_v<remove_cvref_t<_UTuple>, tuple>) + && (tuple_size_v<remove_cvref_t<_UTuple>> == 0) + constexpr const tuple& + operator=(_UTuple&&) const noexcept + { return *this; } + + template<__tuple_like _UTuple> + requires (!__is_tuple_v<_UTuple>) && (tuple_size_v<_UTuple> == 0) + [[nodiscard]] + friend constexpr bool + operator==(const tuple&, const _UTuple&) noexcept + { return true; } + + template<__tuple_like _UTuple> + requires (!__is_tuple_v<_UTuple>) && (tuple_size_v<_UTuple> == 0) + friend constexpr strong_ordering + operator<=>(const tuple&, const _UTuple&) noexcept + { return strong_ordering::equal; } +#endif // C++23 }; #if !(__cpp_concepts && __cpp_consteval && __cpp_conditional_explicit) // !C++20 @@ -2681,54 +2736,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); } /// @cond undocumented - template<size_t, typename, typename, size_t> - struct __make_tuple_impl; - - template<size_t _Idx, typename _Tuple, typename... _Tp, size_t _Nm> - struct __make_tuple_impl<_Idx, tuple<_Tp...>, _Tuple, _Nm> - : __make_tuple_impl<_Idx + 1, - tuple<_Tp..., __tuple_element_t<_Idx, _Tuple>>, - _Tuple, _Nm> - { }; + template<typename _Tuple, typename _Idx_tuple> + struct __do_make_tuple; - template<size_t _Nm, typename _Tuple, typename... _Tp> - struct __make_tuple_impl<_Nm, tuple<_Tp...>, _Tuple, _Nm> + template<typename _Tuple, size_t... _Idx> + struct __do_make_tuple<_Tuple, _Index_tuple<_Idx...>> { - typedef tuple<_Tp...> __type; + using __type = tuple<__tuple_element_t<_Idx, _Tuple>...>; }; - template<typename _Tuple> - struct __do_make_tuple - : __make_tuple_impl<0, tuple<>, _Tuple, tuple_size<_Tuple>::value> - { }; - // Returns the std::tuple equivalent of a tuple-like type. - template<typename _Tuple> + template<typename _Tuple, + typename _Tup = __remove_cvref_t<_Tuple>, + typename _Indices = _Build_index_tuple<tuple_size<_Tup>::value>> struct __make_tuple - : public __do_make_tuple<__remove_cvref_t<_Tuple>> + : __do_make_tuple<_Tup, typename _Indices::__type> { }; - // Combines several std::tuple's into a single one. + // Combines several std::tuple types into a single one. template<typename...> struct __combine_tuples; template<> struct __combine_tuples<> { - typedef tuple<> __type; + using __type = tuple<>; }; template<typename... _Ts> struct __combine_tuples<tuple<_Ts...>> { - typedef tuple<_Ts...> __type; + using __type = tuple<_Ts...>; + }; + + template<typename... _T1s, typename... _T2s> + struct __combine_tuples<tuple<_T1s...>, tuple<_T2s...>> + { + using __type = tuple<_T1s..., _T2s...>; }; - template<typename... _T1s, typename... _T2s, typename... _Rem> - struct __combine_tuples<tuple<_T1s...>, tuple<_T2s...>, _Rem...> + template<typename... _T1s, typename... _T2s, typename... _T3s, + typename... _Rem> + struct __combine_tuples<tuple<_T1s...>, tuple<_T2s...>, tuple<_T3s...>, + _Rem...> { - typedef typename __combine_tuples<tuple<_T1s..., _T2s...>, - _Rem...>::__type __type; + using _First = tuple<_T1s..., _T2s..., _T3s...>; + using _Second = typename __combine_tuples<_Rem...>::__type; + using __type = typename __combine_tuples<_First, _Second>::__type; }; // Computes the result type of tuple_cat given a set of tuple-like types. @@ -2835,6 +2889,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __x.swap(__y); } #if __cpp_lib_ranges_zip // >= C++23 + /// Exchange the values of two const tuples (if const elements can be swapped) template<typename... _Elements> requires (is_swappable_v<const _Elements> && ...) constexpr void @@ -2844,7 +2899,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // C++23 #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 - /// Exchange the values of two const tuples (if const elements can be swapped) + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2766. Swapping non-swappable types template<typename... _Elements> _GLIBCXX20_CONSTEXPR typename enable_if<!__and_<__is_swappable<_Elements>...>::value>::type @@ -2939,19 +2995,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif #ifdef __cpp_lib_make_from_tuple // C++ >= 17 + template <typename _Tp, typename _Tuple, typename _Seq + = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>> + constexpr bool __can_make_from_tuple = false; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3528. make_from_tuple can perform (the equivalent of) a C-style cast + template <typename _Tp, typename _Tuple, size_t... _Idx> + constexpr bool __can_make_from_tuple<_Tp, _Tuple, index_sequence<_Idx...>> + = is_constructible_v<_Tp, + decltype(std::get<_Idx>(std::declval<_Tuple>()))...>; + template <typename _Tp, typename _Tuple, size_t... _Idx> constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>) - { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); } + { + static_assert(__can_make_from_tuple<_Tp, _Tuple, index_sequence<_Idx...>>); + return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); + } #if __cpp_lib_tuple_like // >= C++23 template <typename _Tp, __tuple_like _Tuple> #else template <typename _Tp, typename _Tuple> #endif - constexpr _Tp + constexpr auto make_from_tuple(_Tuple&& __t) noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>) +#ifdef __cpp_concepts // >= C++20 + -> _Tp + requires __can_make_from_tuple<_Tp, _Tuple> +#else + -> __enable_if_t<__can_make_from_tuple<_Tp, _Tuple>, _Tp> +#endif { constexpr size_t __n = tuple_size_v<remove_reference_t<_Tuple>>; #if __has_builtin(__reference_constructs_from_temporary) diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 676cdf2..3f0bcc4e 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -41,11 +41,14 @@ #define __glibcxx_want_bool_constant #define __glibcxx_want_bounded_array_traits +#define __glibcxx_want_common_reference +#define __glibcxx_want_constant_wrapper #define __glibcxx_want_has_unique_object_representations #define __glibcxx_want_integral_constant_callable #define __glibcxx_want_is_aggregate #define __glibcxx_want_is_constant_evaluated #define __glibcxx_want_is_final +#define __glibcxx_want_is_implicit_lifetime #define __glibcxx_want_is_invocable #define __glibcxx_want_is_layout_compatible #define __glibcxx_want_is_nothrow_convertible @@ -280,11 +283,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Forward declarations template<typename> - struct is_reference; - template<typename> - struct is_function; - template<typename> - struct is_void; + struct is_object; template<typename> struct remove_cv; template<typename> @@ -294,21 +293,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename> struct __is_array_unknown_bounds; + // An object type which is not an unbounded array. + // It might still be an incomplete type, but if this is false_type + // then we can be certain it's not a complete object type. + template<typename _Tp> + using __maybe_complete_object_type + = __and_<is_object<_Tp>, __not_<__is_array_unknown_bounds<_Tp>>>; + // Helper functions that return false_type for incomplete classes, // incomplete unions and arrays of known bound from those. - template <typename _Tp, size_t = sizeof(_Tp)> - constexpr true_type __is_complete_or_unbounded(__type_identity<_Tp>) - { return {}; } - - template <typename _TypeIdentity, - typename _NestedType = typename _TypeIdentity::type> - constexpr typename __or_< - is_reference<_NestedType>, - is_function<_NestedType>, - is_void<_NestedType>, - __is_array_unknown_bounds<_NestedType> - >::type __is_complete_or_unbounded(_TypeIdentity) + // More specialized overload for complete object types (returning true_type). + template<typename _Tp, + typename = __enable_if_t<__maybe_complete_object_type<_Tp>::value>, + size_t = sizeof(_Tp)> + constexpr true_type + __is_complete_or_unbounded(__type_identity<_Tp>) + { return {}; }; + + // Less specialized overload for reference and unknown-bound array types + // (returning true_type), and incomplete types (returning false_type). + template<typename _TypeIdentity, + typename _NestedType = typename _TypeIdentity::type> + constexpr typename __not_<__maybe_complete_object_type<_NestedType>>::type + __is_complete_or_unbounded(_TypeIdentity) { return {}; } // __remove_cv_t (std::remove_cv_t for C++11). @@ -459,6 +467,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_3> : public true_type { }; #endif + +#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ + __extension__ + template<> + struct __is_integral_helper<__int128> + : public true_type { }; + + __extension__ + template<> + struct __is_integral_helper<unsigned __int128> + : public true_type { }; +#endif + /// @endcond /// is_integral @@ -514,7 +535,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public true_type { }; #endif -#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128) +#ifdef _GLIBCXX_USE_FLOAT128 template<> struct __is_floating_point_helper<__float128> : public true_type { }; @@ -805,7 +826,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Check if a type is one of the signed integer types. __extension__ template<typename _Tp> - using __is_signed_integer = __is_one_of<__remove_cv_t<_Tp>, + using __is_signed_integer = __is_one_of<_Tp, signed char, signed short, signed int, signed long, signed long long #if defined(__GLIBCXX_TYPE_INT_N_0) @@ -820,12 +841,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if defined(__GLIBCXX_TYPE_INT_N_3) , signed __GLIBCXX_TYPE_INT_N_3 #endif +#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ + , signed __int128 +#endif >; // Check if a type is one of the unsigned integer types. __extension__ template<typename _Tp> - using __is_unsigned_integer = __is_one_of<__remove_cv_t<_Tp>, + using __is_unsigned_integer = __is_one_of<_Tp, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long #if defined(__GLIBCXX_TYPE_INT_N_0) @@ -840,11 +864,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if defined(__GLIBCXX_TYPE_INT_N_3) , unsigned __GLIBCXX_TYPE_INT_N_3 #endif +#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ + , unsigned __int128 +#endif >; // Check if a type is one of the signed or unsigned integer types. + // i.e. an integral type except bool, char, wchar_t, and charN_t. template<typename _Tp> - using __is_standard_integer + using __is_signed_or_unsigned_integer = __or_<__is_signed_integer<_Tp>, __is_unsigned_integer<_Tp>>; // __void_t (std::void_t for C++11) @@ -1036,9 +1064,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_array_unknown_bounds<_Tp[]> : public true_type { }; + /// @endcond // Destructible and constructible type properties. +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible) + /// is_destructible + template<typename _Tp> + struct is_destructible + : public __bool_constant<__is_destructible(_Tp)> + { }; +#else + /// @cond undocumented + // In N3290 is_destructible does not say anything about function // types and abstract types, see LWG 2049. This implementation // describes function types as non-destructible and all complete @@ -1090,7 +1128,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; +#endif +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible) + /// is_nothrow_destructible + template<typename _Tp> + struct is_nothrow_destructible + : public __bool_constant<__is_nothrow_destructible(_Tp)> + { }; +#else /// @cond undocumented // is_nothrow_destructible requires that is_destructible is @@ -1144,6 +1190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; +#endif /// @cond undocumented template<typename _Tp, typename... _Args> @@ -1451,6 +1498,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION "template argument must be a complete class or an unbounded array"); }; +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible) + /// is_trivially_destructible + template<typename _Tp> + struct is_trivially_destructible + : public __bool_constant<__is_trivially_destructible(_Tp)> + { }; +#else /// is_trivially_destructible template<typename _Tp> struct is_trivially_destructible @@ -1460,7 +1514,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; - +#endif /// has_virtual_destructor template<typename _Tp> @@ -1896,6 +1950,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __make_unsigned<__GLIBCXX_TYPE_INT_N_3> { using __type = unsigned __GLIBCXX_TYPE_INT_N_3; }; #endif +#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ + __extension__ + template<> + struct __make_unsigned<__int128> + { using __type = unsigned __int128; }; +#endif // Select between integral and enum: not possible to be both. template<typename _Tp, @@ -1942,8 +2002,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : __make_unsigned_selector_base { // With -fshort-enums, an enum may be as small as a char. + __extension__ using _UInts = _List<unsigned char, unsigned short, unsigned int, - unsigned long, unsigned long long>; + unsigned long, unsigned long long +#ifdef __SIZEOF_INT128__ + , unsigned __int128 +#endif + >; using __unsigned_type = typename __select<sizeof(_Tp), _UInts>::__type; @@ -2056,6 +2121,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __make_signed<unsigned __GLIBCXX_TYPE_INT_N_3> { using __type = __GLIBCXX_TYPE_INT_N_3; }; #endif +#if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ + __extension__ + template<> + struct __make_signed<unsigned __int128> + { using __type = __int128; }; +#endif // Select between integral and enum: not possible to be both. template<typename _Tp, @@ -3212,7 +3283,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Fn, typename... _ArgTypes> struct __is_invocable +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable) + : __bool_constant<__is_invocable(_Fn, _ArgTypes...)> +#else : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type +#endif { }; template<typename _Fn, typename _Tp, typename... _Args> @@ -3263,8 +3338,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // __is_nothrow_invocable (std::is_nothrow_invocable for C++11) template<typename _Fn, typename... _Args> struct __is_nothrow_invocable +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable) + : __bool_constant<__is_nothrow_invocable(_Fn, _Args...)> +#else : __and_<__is_invocable<_Fn, _Args...>, __call_is_nothrow_<_Fn, _Args...>>::type +#endif { }; #pragma GCC diagnostic push @@ -3573,8 +3652,13 @@ template <typename _Tp> inline constexpr bool is_move_assignable_v = __is_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible) +template <typename _Tp> + inline constexpr bool is_destructible_v = __is_destructible(_Tp); +#else template <typename _Tp> inline constexpr bool is_destructible_v = is_destructible<_Tp>::value; +#endif template <typename _Tp, typename... _Args> inline constexpr bool is_trivially_constructible_v @@ -3601,7 +3685,11 @@ template <typename _Tp> = __is_trivially_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); -#if __cpp_concepts +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible) +template <typename _Tp> + inline constexpr bool is_trivially_destructible_v + = __is_trivially_destructible(_Tp); +#elif __cpp_concepts template <typename _Tp> inline constexpr bool is_trivially_destructible_v = false; @@ -3646,9 +3734,15 @@ template <typename _Tp> inline constexpr bool is_nothrow_move_assignable_v = __is_nothrow_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>); +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible) +template <typename _Tp> + inline constexpr bool is_nothrow_destructible_v + = __is_nothrow_destructible(_Tp); +#else template <typename _Tp> inline constexpr bool is_nothrow_destructible_v = is_nothrow_destructible<_Tp>::value; +#endif template <typename _Tp> inline constexpr bool has_virtual_destructor_v @@ -3704,10 +3798,19 @@ template <typename _From, typename _To> inline constexpr bool is_convertible_v = is_convertible<_From, _To>::value; #endif template<typename _Fn, typename... _Args> - inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value; + inline constexpr bool is_invocable_v +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable) + = __is_invocable(_Fn, _Args...); +#else + = is_invocable<_Fn, _Args...>::value; +#endif template<typename _Fn, typename... _Args> inline constexpr bool is_nothrow_invocable_v +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable) + = __is_nothrow_invocable(_Fn, _Args...); +#else = is_nothrow_invocable<_Fn, _Args...>::value; +#endif template<typename _Ret, typename _Fn, typename... _Args> inline constexpr bool is_invocable_r_v = is_invocable_r<_Ret, _Fn, _Args...>::value; @@ -3959,6 +4062,22 @@ template<typename _Ret, typename _Fn, typename... _Args> # endif #endif +#ifdef __cpp_lib_is_implicit_lifetime // C++ >= 23 + /// True if the type is an implicit-lifetime type. + /// @since C++23 + + template<typename _Tp> + struct is_implicit_lifetime + : bool_constant<__builtin_is_implicit_lifetime(_Tp)> + { }; + + /// @ingroup variable_templates + /// @since C++23 + template<typename _Tp> + inline constexpr bool is_implicit_lifetime_v + = __builtin_is_implicit_lifetime(_Tp); +#endif + #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp /// True if _Tp is a reference type, a _Up value can be bound to _Tp in /// direct-initialization, and a temporary object would be bound to @@ -4002,7 +4121,8 @@ template<typename _Ret, typename _Fn, typename... _Args> #ifdef __cpp_lib_is_constant_evaluated // C++ >= 20 && HAVE_IS_CONST_EVAL /// Returns true only when called during constant evaluation. /// @since C++20 - constexpr inline bool + [[__gnu__::__always_inline__]] + constexpr bool is_constant_evaluated() noexcept { #if __cpp_if_consteval >= 202106L @@ -4113,7 +4233,7 @@ template<typename _Ret, typename _Fn, typename... _Args> { using type = _Tp0; }; /// @cond undocumented - template<typename _Tp1, typename _Tp2, int _Bullet = 1, typename = void> + template<typename _Tp1, typename _Tp2, int _Bullet = 1> struct __common_reference_impl : __common_reference_impl<_Tp1, _Tp2, _Bullet + 1> { }; @@ -4126,46 +4246,38 @@ template<typename _Ret, typename _Fn, typename... _Args> // If T1 and T2 are reference types and COMMON-REF(T1, T2) is well-formed, ... template<typename _Tp1, typename _Tp2> - struct __common_reference_impl<_Tp1&, _Tp2&, 1, - void_t<__common_ref<_Tp1&, _Tp2&>>> - { using type = __common_ref<_Tp1&, _Tp2&>; }; - - template<typename _Tp1, typename _Tp2> - struct __common_reference_impl<_Tp1&&, _Tp2&&, 1, - void_t<__common_ref<_Tp1&&, _Tp2&&>>> - { using type = __common_ref<_Tp1&&, _Tp2&&>; }; - - template<typename _Tp1, typename _Tp2> - struct __common_reference_impl<_Tp1&, _Tp2&&, 1, - void_t<__common_ref<_Tp1&, _Tp2&&>>> - { using type = __common_ref<_Tp1&, _Tp2&&>; }; - - template<typename _Tp1, typename _Tp2> - struct __common_reference_impl<_Tp1&&, _Tp2&, 1, - void_t<__common_ref<_Tp1&&, _Tp2&>>> - { using type = __common_ref<_Tp1&&, _Tp2&>; }; + requires is_reference_v<_Tp1> && is_reference_v<_Tp2> + && requires { typename __common_ref<_Tp1, _Tp2>; } +#if __cpp_lib_common_reference // C++ >= 20 + && is_convertible_v<add_pointer_t<_Tp1>, + add_pointer_t<__common_ref<_Tp1, _Tp2>>> + && is_convertible_v<add_pointer_t<_Tp2>, + add_pointer_t<__common_ref<_Tp1, _Tp2>>> +#endif + struct __common_reference_impl<_Tp1, _Tp2, 1> + { using type = __common_ref<_Tp1, _Tp2>; }; // Otherwise, if basic_common_reference<...>::type is well-formed, ... template<typename _Tp1, typename _Tp2> - struct __common_reference_impl<_Tp1, _Tp2, 2, - void_t<__basic_common_ref<_Tp1, _Tp2>>> + requires requires { typename __basic_common_ref<_Tp1, _Tp2>; } + struct __common_reference_impl<_Tp1, _Tp2, 2> { using type = __basic_common_ref<_Tp1, _Tp2>; }; // Otherwise, if COND-RES(T1, T2) is well-formed, ... template<typename _Tp1, typename _Tp2> - struct __common_reference_impl<_Tp1, _Tp2, 3, - void_t<__cond_res<_Tp1, _Tp2>>> + requires requires { typename __cond_res<_Tp1, _Tp2>; } + struct __common_reference_impl<_Tp1, _Tp2, 3> { using type = __cond_res<_Tp1, _Tp2>; }; // Otherwise, if common_type_t<T1, T2> is well-formed, ... template<typename _Tp1, typename _Tp2> - struct __common_reference_impl<_Tp1, _Tp2, 4, - void_t<common_type_t<_Tp1, _Tp2>>> + requires requires { typename common_type_t<_Tp1, _Tp2>; } + struct __common_reference_impl<_Tp1, _Tp2, 4> { using type = common_type_t<_Tp1, _Tp2>; }; // Otherwise, there shall be no member type. template<typename _Tp1, typename _Tp2> - struct __common_reference_impl<_Tp1, _Tp2, 5, void> + struct __common_reference_impl<_Tp1, _Tp2, 5> { }; // Otherwise, if sizeof...(T) is greater than two, ... @@ -4184,7 +4296,399 @@ template<typename _Ret, typename _Fn, typename... _Args> { }; /// @endcond -#endif // C++2a +#endif // C++20 + +#if __cplusplus >= 201103L + // Stores a tuple of indices. Used by tuple and pair, and by bind() to + // extract the elements in a tuple. + template<size_t... _Indexes> struct _Index_tuple { }; + + // Builds an _Index_tuple<0, 1, 2, ..., _Num-1>. + template<size_t _Num> + struct _Build_index_tuple + { +#if __has_builtin(__make_integer_seq) + template<typename, size_t... _Indices> + using _IdxTuple = _Index_tuple<_Indices...>; + + // Clang defines __make_integer_seq for this purpose. + using __type = __make_integer_seq<_IdxTuple, size_t, _Num>; +#else + // For GCC and other compilers, use __integer_pack instead. + using __type = _Index_tuple<__integer_pack(_Num)...>; +#endif + }; +#endif // C++11 + +#ifdef __cpp_lib_constant_wrapper // C++ >= 26 + template<typename _Tp> + struct _CwFixedValue + { + using __type = _Tp; + + constexpr + _CwFixedValue(__type __v) noexcept + : _M_data(__v) { } + + __type _M_data; + }; + + template<typename _Tp, size_t _Extent> + struct _CwFixedValue<_Tp[_Extent]> + { + using __type = _Tp[_Extent]; + + constexpr + _CwFixedValue(_Tp (&__arr)[_Extent]) noexcept + : _CwFixedValue(__arr, typename _Build_index_tuple<_Extent>::__type()) + { } + + template<size_t... _Indices> + constexpr + _CwFixedValue(_Tp (&__arr)[_Extent], _Index_tuple<_Indices...>) noexcept + : _M_data{__arr[_Indices]...} + { } + + _Tp _M_data[_Extent]; + }; + + template<typename _Tp, size_t _Extent> + _CwFixedValue(_Tp (&)[_Extent]) -> _CwFixedValue<_Tp[_Extent]>; + + template<_CwFixedValue _Xv, + typename = typename decltype(_CwFixedValue(_Xv))::__type> + struct constant_wrapper; + + template<typename _Tp> + concept _ConstExprParam = requires + { + typename constant_wrapper<_Tp::value>; + }; + + struct _CwOperators + { + template<_ConstExprParam _Tp> + friend constexpr auto + operator+(_Tp) noexcept -> constant_wrapper<(+_Tp::value)> + { return {}; } + + template<_ConstExprParam _Tp> + friend constexpr auto + operator-(_Tp) noexcept -> constant_wrapper<(-_Tp::value)> + { return {}; } + + template<_ConstExprParam _Tp> + friend constexpr auto + operator~(_Tp) noexcept -> constant_wrapper<(~_Tp::value)> + { return {}; } + + template<_ConstExprParam _Tp> + friend constexpr auto + operator!(_Tp) noexcept -> constant_wrapper<(!_Tp::value)> + { return {}; } + + template<_ConstExprParam _Tp> + friend constexpr auto + operator&(_Tp) noexcept -> constant_wrapper<(&_Tp::value)> + { return {}; } + + template<_ConstExprParam _Tp> + friend constexpr auto + operator*(_Tp) noexcept -> constant_wrapper<(*_Tp::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator+(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value + _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator-(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value - _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator*(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value * _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator/(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value / _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator%(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value % _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator<<(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value << _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator>>(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value >> _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator&(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value & _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator|(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value | _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator^(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value ^ _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + requires (!is_constructible_v<bool, decltype(_Left::value)> + || !is_constructible_v<bool, decltype(_Right::value)>) + friend constexpr auto + operator&&(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value && _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + requires (!is_constructible_v<bool, decltype(_Left::value)> + || !is_constructible_v<bool, decltype(_Right::value)>) + friend constexpr auto + operator||(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value || _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator<=>(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value <=> _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator<(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value < _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator<=(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value <= _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator==(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value == _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator!=(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value != _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator>(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value > _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator>=(_Left, _Right) noexcept + -> constant_wrapper<(_Left::value >= _Right::value)> + { return {}; } + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator,(_Left, _Right) noexcept = delete; + + template<_ConstExprParam _Left, _ConstExprParam _Right> + friend constexpr auto + operator->*(_Left, _Right) noexcept + -> constant_wrapper<_Left::value->*(_Right::value)> + { return {}; } + + template<_ConstExprParam _Tp, _ConstExprParam... _Args> + constexpr auto + operator()(this _Tp, _Args...) noexcept + requires + requires(_Args...) { constant_wrapper<_Tp::value(_Args::value...)>(); } + { return constant_wrapper<_Tp::value(_Args::value...)>{}; } + + template<_ConstExprParam _Tp, _ConstExprParam... _Args> + constexpr auto + operator[](this _Tp, _Args...) noexcept + -> constant_wrapper<(_Tp::value[_Args::value...])> + { return {}; } + + template<_ConstExprParam _Tp> + constexpr auto + operator++(this _Tp) noexcept + requires requires(_Tp::value_type __x) { ++__x; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return ++__x; }()>{}; + } + + template<_ConstExprParam _Tp> + constexpr auto + operator++(this _Tp, int) noexcept + requires requires(_Tp::value_type __x) { __x++; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x++; }()>{}; + } + + template<_ConstExprParam _Tp> + constexpr auto + operator--(this _Tp) noexcept + requires requires(_Tp::value_type __x) { --__x; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return --__x; }()>{}; + } + + template<_ConstExprParam _Tp> + constexpr auto + operator--(this _Tp, int) noexcept + requires requires(_Tp::value_type __x) { __x--; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x--; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator+=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x += _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x += _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator-=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x -= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x -= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator*=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x *= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x *= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator/=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x /= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x /= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator%=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x %= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x %= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator&=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x &= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x &= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator|=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x |= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x |= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator^=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x ^= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x ^= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator<<=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x <<= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x <<= _Right::value; }()>{}; + } + + template<_ConstExprParam _Tp, _ConstExprParam _Right> + constexpr auto + operator>>=(this _Tp, _Right) noexcept + requires requires(_Tp::value_type __x) { __x >>= _Right::value; } + { + return constant_wrapper< + [] { auto __x = _Tp::value; return __x >>= _Right::value; }()>{}; + } + }; + + template<_CwFixedValue _Xv, typename> + struct constant_wrapper : _CwOperators + { + static constexpr const auto& value = _Xv._M_data; + using type = constant_wrapper; + using value_type = typename decltype(_Xv)::__type; + + template<_ConstExprParam _Right> + constexpr auto + operator=(_Right) const noexcept + requires requires(value_type __x) { __x = _Right::value; } + { + return constant_wrapper< + [] { auto __x = value; return __x = _Right::value; }()>{}; + } + + constexpr + operator decltype(value)() const noexcept + { return value; } + }; + + template<_CwFixedValue _Tp> + constexpr auto cw = constant_wrapper<_Tp>{}; +#endif /// @} group metaprogramming diff --git a/libstdc++-v3/include/std/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..0f6dd82 100644 --- a/libstdc++-v3/include/std/utility +++ b/libstdc++-v3/include/std/utility @@ -78,7 +78,7 @@ #include <bits/utility.h> #if __cplusplus >= 202002L -#include <ext/numeric_traits.h> // __is_standard_integer, __int_traits +#include <bits/intcmp.h> #endif #if __cplusplus > 202302L @@ -98,6 +98,7 @@ #define __glibcxx_want_tuple_element_t #define __glibcxx_want_tuples_by_type #define __glibcxx_want_unreachable +#define __glibcxx_want_observable_checkpoint #define __glibcxx_want_tuple_like #define __glibcxx_want_constrained_equality #include <bits/version.h> @@ -128,80 +129,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void as_const(const _Tp&&) = delete; #endif -#ifdef __cpp_lib_integer_comparison_functions // C++ >= 20 - template<typename _Tp, typename _Up> - constexpr bool - cmp_equal(_Tp __t, _Up __u) noexcept - { - static_assert(__is_standard_integer<_Tp>::value); - static_assert(__is_standard_integer<_Up>::value); - - if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) - return __t == __u; - else if constexpr (is_signed_v<_Tp>) - return __t >= 0 && make_unsigned_t<_Tp>(__t) == __u; - else - return __u >= 0 && __t == make_unsigned_t<_Up>(__u); - } - - template<typename _Tp, typename _Up> - constexpr bool - cmp_not_equal(_Tp __t, _Up __u) noexcept - { return !std::cmp_equal(__t, __u); } - - template<typename _Tp, typename _Up> - constexpr bool - cmp_less(_Tp __t, _Up __u) noexcept - { - static_assert(__is_standard_integer<_Tp>::value); - static_assert(__is_standard_integer<_Up>::value); - - if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) - return __t < __u; - else if constexpr (is_signed_v<_Tp>) - return __t < 0 || make_unsigned_t<_Tp>(__t) < __u; - else - return __u >= 0 && __t < make_unsigned_t<_Up>(__u); - } - - template<typename _Tp, typename _Up> - constexpr bool - cmp_greater(_Tp __t, _Up __u) noexcept - { return std::cmp_less(__u, __t); } - - template<typename _Tp, typename _Up> - constexpr bool - cmp_less_equal(_Tp __t, _Up __u) noexcept - { return !std::cmp_less(__u, __t); } - - template<typename _Tp, typename _Up> - constexpr bool - cmp_greater_equal(_Tp __t, _Up __u) noexcept - { return !std::cmp_less(__t, __u); } - - template<typename _Res, typename _Tp> - constexpr bool - in_range(_Tp __t) noexcept - { - static_assert(__is_standard_integer<_Res>::value); - static_assert(__is_standard_integer<_Tp>::value); - using __gnu_cxx::__int_traits; - - if constexpr (is_signed_v<_Tp> == is_signed_v<_Res>) - return __int_traits<_Res>::__min <= __t - && __t <= __int_traits<_Res>::__max; - else if constexpr (is_signed_v<_Tp>) - return __t >= 0 - && make_unsigned_t<_Tp>(__t) <= __int_traits<_Res>::__max; - else - return __t <= make_unsigned_t<_Res>(__int_traits<_Res>::__max); - } -#endif // __cpp_lib_integer_comparison_functions - #ifdef __cpp_lib_to_underlying // C++ >= 23 /// Convert an object of enumeration type to its underlying type. template<typename _Tp> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr underlying_type_t<_Tp> to_underlying(_Tp __value) noexcept { return static_cast<underlying_type_t<_Tp>>(__value); } @@ -234,6 +165,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif + +#ifdef __cpp_lib_observable_checkpoint // C++ >= 26 + /// Informs the compiler that prior actions are considered observable. + /** + * This may be used to limit the extent to which optimisations based on the + * assumed unreachability of undefined behaviour can propagate to earlier + * code. + * + * @since C++26 + */ + [[__gnu__::__always_inline__]] + inline void + observable_checkpoint() noexcept + { + return __builtin_observable_checkpoint(); + } +#endif + _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/std/valarray b/libstdc++-v3/include/std/valarray index 82b58ef..ac15e79 100644 --- a/libstdc++-v3/include/std/valarray +++ b/libstdc++-v3/include/std/valarray @@ -720,7 +720,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION valarray<_Tp>::~valarray() _GLIBCXX_NOEXCEPT { std::__valarray_destroy_elements(_M_data, _M_data + _M_size); - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); } template<typename _Tp> @@ -736,7 +736,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_data) { std::__valarray_destroy_elements(_M_data, _M_data + _M_size); - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); } _M_size = __v._M_size; _M_data = __valarray_get_storage<_Tp>(_M_size); @@ -754,7 +754,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_data) { std::__valarray_destroy_elements(_M_data, _M_data + _M_size); - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); } _M_size = __v._M_size; _M_data = __v._M_data; @@ -776,7 +776,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_data) { std::__valarray_destroy_elements(_M_data, _M_data + _M_size); - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); } _M_size = __l.size(); _M_data = __valarray_get_storage<_Tp>(_M_size); @@ -854,7 +854,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_data) { std::__valarray_destroy_elements(_M_data, _M_data + _M_size); - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); } _M_size = __e.size(); _M_data = __valarray_get_storage<_Tp>(_M_size); @@ -1049,7 +1049,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::__valarray_destroy_elements(_M_data, _M_data + _M_size); if (_M_size != __n) { - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); _M_size = __n; _M_data = __valarray_get_storage<_Tp>(__n); } diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index ec46ff1..f2f5583 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -393,8 +393,29 @@ namespace __variant _Variadic_union(in_place_index_t<_Np>, _Args&&...) = delete; }; - template<bool __trivially_destructible, typename _First, typename... _Rest> - union _Variadic_union<__trivially_destructible, _First, _Rest...> + template<typename _First, typename... _Rest> + union _Variadic_union<true, _First, _Rest...> + { + constexpr _Variadic_union() : _M_rest() { } + + template<typename... _Args> + constexpr + _Variadic_union(in_place_index_t<0>, _Args&&... __args) + : _M_first(in_place_index<0>, std::forward<_Args>(__args)...) + { } + + template<size_t _Np, typename... _Args> + constexpr + _Variadic_union(in_place_index_t<_Np>, _Args&&... __args) + : _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...) + { } + + _Uninitialized<_First> _M_first; + _Variadic_union<true, _Rest...> _M_rest; + }; + + template<typename _First, typename... _Rest> + union _Variadic_union<false, _First, _Rest...> { constexpr _Variadic_union() : _M_rest() { } @@ -410,24 +431,19 @@ namespace __variant : _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...) { } -#if __cpp_lib_variant >= 202106L _Variadic_union(const _Variadic_union&) = default; _Variadic_union(_Variadic_union&&) = default; _Variadic_union& operator=(const _Variadic_union&) = default; _Variadic_union& operator=(_Variadic_union&&) = default; - ~_Variadic_union() = default; - // If any alternative type is not trivially destructible then we need a // user-provided destructor that does nothing. The active alternative // will be destroyed by _Variant_storage::_M_reset() instead of here. - constexpr ~_Variadic_union() - requires (!__trivially_destructible) + _GLIBCXX20_CONSTEXPR ~_Variadic_union() { } -#endif _Uninitialized<_First> _M_first; - _Variadic_union<__trivially_destructible, _Rest...> _M_rest; + _Variadic_union<(is_trivially_destructible_v<_Rest> && ...), _Rest...> _M_rest; }; // _Never_valueless_alt is true for variant alternatives that can @@ -1387,6 +1403,8 @@ namespace __detail::__variant noexcept(noexcept(__lhs.swap(__rhs))) { __lhs.swap(__rhs); } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2766. Swapping non-swappable types template<typename... _Types> enable_if_t<!((is_move_constructible_v<_Types> && ...) && (is_swappable_v<_Types> && ...))> diff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector index 8bb2543..375011f 100644 --- a/libstdc++-v3/include/std/vector +++ b/libstdc++-v3/include/std/vector @@ -67,7 +67,6 @@ #include <bits/stl_uninitialized.h> #include <bits/stl_vector.h> #include <bits/stl_bvector.h> -#include <bits/refwrap.h> #include <bits/range_access.h> #ifndef _GLIBCXX_EXPORT_TEMPLATE @@ -81,6 +80,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 @@ -112,20 +112,16 @@ namespace std _GLIBCXX_VISIBILITY(default) _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Alloc, typename _Predicate> - _GLIBCXX20_CONSTEXPR - inline typename vector<_Tp, _Alloc>::size_type - erase_if(vector<_Tp, _Alloc>& __cont, _Predicate __pred) + constexpr typename _GLIBCXX_STD_C::vector<_Tp, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::vector<_Tp, _Alloc>& __cont, _Predicate __pred) { - using namespace __gnu_cxx; - _GLIBCXX_STD_C::vector<_Tp, _Alloc>& __ucont = __cont; const auto __osz = __cont.size(); - const auto __end = __ucont.end(); - auto __removed = std::__remove_if(__ucont.begin(), __end, - __ops::__pred_iter(std::ref(__pred))); + const auto __end = __cont.end(); + auto __removed = std::__remove_if(__cont.begin(), __end, + std::move(__pred)); if (__removed != __end) { - __cont.erase(__niter_wrap(__cont.begin(), __removed), - __cont.end()); + __cont.erase(__removed, __end); return __osz - __cont.size(); } @@ -134,25 +130,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Alloc, typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)> - _GLIBCXX20_CONSTEXPR - inline typename vector<_Tp, _Alloc>::size_type - erase(vector<_Tp, _Alloc>& __cont, const _Up& __value) - { - using namespace __gnu_cxx; - _GLIBCXX_STD_C::vector<_Tp, _Alloc>& __ucont = __cont; - const auto __osz = __cont.size(); - const auto __end = __ucont.end(); - auto __removed = std::__remove_if(__ucont.begin(), __end, - __ops::__iter_equals_val(__value)); - if (__removed != __end) - { - __cont.erase(__niter_wrap(__cont.begin(), __removed), - __cont.end()); - return __osz - __cont.size(); - } + constexpr typename _GLIBCXX_STD_C::vector<_Tp, _Alloc>::size_type + erase(_GLIBCXX_STD_C::vector<_Tp, _Alloc>& __cont, const _Up& __value) + { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); } - return 0; - } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cpp_lib_erase_if @@ -185,6 +166,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: __format::__formatter_int<_CharT> _M_f; }; + +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization<_GLIBCXX_STD_C::_Bit_reference> = true; +#endif + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __glibcxx_format_ranges |
