xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/bits/max_size_type.h (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 // <max_size_type.h> -*- C++ -*-
2 
3 // Copyright (C) 2019-2022 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 /** @file bits/max_size_type.h
26  *  This is an internal header file, included by other library headers.
27  *  Do not attempt to use it directly. @headername{iterator}
28  */
29 
30 #ifndef _GLIBCXX_MAX_SIZE_TYPE_H
31 #define _GLIBCXX_MAX_SIZE_TYPE_H 1
32 
33 #pragma GCC system_header
34 
35 #if __cplusplus > 201703L && __cpp_lib_concepts
36 #include <ext/numeric_traits.h>
37 #include <numbers>
38 
39 // This header implements unsigned and signed integer-class types (as per
40 // [iterator.concept.winc]) that are one bit wider than the widest supported
41 // integer type.
42 //
43 // The set of integer types we consider includes __int128 and unsigned __int128
44 // (when they exist), even though they are really integer types only in GNU
45 // mode.  This is to obtain a consistent ABI for these integer-class types
46 // across strict mode and GNU mode.
47 
_GLIBCXX_VISIBILITY(default)48 namespace std _GLIBCXX_VISIBILITY(default)
49 {
50 _GLIBCXX_BEGIN_NAMESPACE_VERSION
51 
52 template<typename _Tp>
53   struct numeric_limits;
54 
55 namespace ranges
56 {
57   namespace __detail
58   {
59     class __max_size_type
60     {
61     public:
62       __max_size_type() = default;
63 
64       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
65 	constexpr
66 	__max_size_type(_Tp __i) noexcept
67 	  : _M_val(__i), _M_msb(__i < 0)
68 	{ }
69 
70       constexpr explicit
71       __max_size_type(const __max_diff_type& __d) noexcept;
72 
73       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
74 	constexpr explicit
75 	operator _Tp() const noexcept
76 	{ return _M_val; }
77 
78       constexpr explicit
79       operator bool() const noexcept
80       { return _M_val != 0 || _M_msb != 0; }
81 
82       constexpr __max_size_type
83       operator+() const noexcept
84       { return *this; }
85 
86       constexpr __max_size_type
87       operator~() const noexcept
88       { return __max_size_type{~_M_val, !_M_msb}; }
89 
90       constexpr __max_size_type
91       operator-() const noexcept
92       { return operator~() + 1; }
93 
94       constexpr __max_size_type&
95       operator++() noexcept
96       { return *this += 1; }
97 
98       constexpr __max_size_type
99       operator++(int) noexcept
100       {
101 	auto __tmp = *this;
102 	++*this;
103 	return __tmp;
104       }
105 
106       constexpr __max_size_type&
107       operator--() noexcept
108       { return *this -= 1; }
109 
110       constexpr __max_size_type
111       operator--(int) noexcept
112       {
113 	auto __tmp = *this;
114 	--*this;
115 	return __tmp;
116       }
117 
118       constexpr __max_size_type&
119       operator+=(const __max_size_type& __r) noexcept
120       {
121 	const auto __sum = _M_val + __r._M_val;
122 	const bool __overflow = (__sum < _M_val);
123 	_M_msb = _M_msb ^ __r._M_msb ^ __overflow;
124 	_M_val = __sum;
125 	return *this;
126       }
127 
128       constexpr __max_size_type&
129       operator-=(const __max_size_type& __r) noexcept
130       { return *this += -__r; }
131 
132       constexpr __max_size_type&
133       operator*=(__max_size_type __r) noexcept
134       {
135 	constexpr __max_size_type __threshold
136 	  = __rep(1) << (_S_rep_bits / 2 - 1);
137 	if (_M_val < __threshold && __r < __threshold)
138 	  // When both operands are below this threshold then the
139 	  // multiplication can be safely computed in the base precision.
140 	  _M_val = _M_val * __r._M_val;
141 	else
142 	  {
143 	    // Otherwise, perform the multiplication in four steps, by
144 	    // decomposing the LHS and the RHS into 2*x+a and 2*y+b,
145 	    // respectively, and computing 4*x*y + 2*x*b + 2*y*a + a*b.
146 	    const bool __lsb = _M_val & 1;
147 	    const bool __rlsb = __r._M_val & 1;
148 	    *this >>= 1;
149 	    __r >>= 1;
150 	    _M_val = (2 * _M_val * __r._M_val
151 		      + _M_val * __rlsb + __r._M_val * __lsb);
152 	    *this <<= 1;
153 	    *this += __rlsb * __lsb;
154 	  }
155 
156 	return *this;
157       }
158 
159       constexpr __max_size_type&
160       operator/=(const __max_size_type& __r) noexcept
161       {
162 	__glibcxx_assert(__r != 0);
163 
164 	if (!_M_msb && !__r._M_msb) [[likely]]
165 	  _M_val /= __r._M_val;
166 	else if (_M_msb && __r._M_msb)
167 	  {
168 	    _M_val = (_M_val >= __r._M_val);
169 	    _M_msb = 0;
170 	  }
171 	else if (!_M_msb && __r._M_msb)
172 	  _M_val = 0;
173 	else if (_M_msb && !__r._M_msb)
174 	  {
175 	    // The non-trivial case: the dividend has its MSB set and the
176 	    // divisor doesn't.  In this case we compute ((LHS/2)/RHS)*2
177 	    // in the base precision.  This quantity is either the true
178 	    // quotient or one less than the true quotient.
179 	    const auto __orig = *this;
180 	    *this >>= 1;
181 	    _M_val /= __r._M_val;
182 	    *this <<= 1;
183 	    if (__orig - *this * __r >= __r)
184 	      ++_M_val;
185 	  }
186 	return *this;
187       }
188 
189       constexpr __max_size_type&
190       operator%=(const __max_size_type& __r) noexcept
191       {
192 	if (!_M_msb && !__r._M_msb) [[likely]]
193 	  _M_val %= __r._M_val;
194 	else
195 	  *this -= (*this / __r) * __r;
196 	return *this;
197       }
198 
199       constexpr __max_size_type&
200       operator<<=(const __max_size_type& __r) noexcept
201       {
202 	__glibcxx_assert(__r <= _S_rep_bits);
203 	if (__r != 0)
204 	  {
205 	    _M_msb = (_M_val >> (_S_rep_bits - __r._M_val)) & 1;
206 
207 	    if (__r._M_val == _S_rep_bits) [[unlikely]]
208 	      _M_val = 0;
209 	    else
210 	      _M_val <<= __r._M_val;
211 	  }
212 	return *this;
213       }
214 
215       constexpr __max_size_type&
216       operator>>=(const __max_size_type& __r) noexcept
217       {
218 	__glibcxx_assert(__r <= _S_rep_bits);
219 	if (__r != 0)
220 	  {
221 	    if (__r._M_val == _S_rep_bits) [[unlikely]]
222 	      _M_val = 0;
223 	    else
224 	      _M_val >>= __r._M_val;
225 
226 	    if (_M_msb) [[unlikely]]
227 	      {
228 		_M_val |= __rep(1) << (_S_rep_bits - __r._M_val);
229 		_M_msb = 0;
230 	      }
231 	  }
232 	return *this;
233       }
234 
235       constexpr __max_size_type&
236       operator&=(const __max_size_type& __r) noexcept
237       {
238 	_M_val &= __r._M_val;
239 	_M_msb &= __r._M_msb;
240 	return *this;
241       }
242 
243       constexpr __max_size_type&
244       operator|=(const __max_size_type& __r) noexcept
245       {
246 	_M_val |= __r._M_val;
247 	_M_msb |= __r._M_msb;
248 	return *this;
249       }
250 
251       constexpr __max_size_type&
252       operator^=(const __max_size_type& __r) noexcept
253       {
254 	_M_val ^= __r._M_val;
255 	_M_msb ^= __r._M_msb;
256 	return *this;
257       }
258 
259       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
260 	friend constexpr _Tp&
261 	operator+=(_Tp& __a, const __max_size_type& __b) noexcept
262 	{ return (__a = static_cast<_Tp>(__a + __b)); }
263 
264       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
265 	friend constexpr _Tp&
266 	operator-=(_Tp& __a, const __max_size_type& __b) noexcept
267 	{ return (__a = static_cast<_Tp>(__a - __b)); }
268 
269       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
270 	friend constexpr _Tp&
271 	operator*=(_Tp& __a, const __max_size_type& __b) noexcept
272 	{ return (__a = static_cast<_Tp>(__a * __b)); }
273 
274       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
275 	friend constexpr _Tp&
276 	operator/=(_Tp& __a, const __max_size_type& __b) noexcept
277 	{ return (__a = static_cast<_Tp>(__a / __b)); }
278 
279       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
280 	friend constexpr _Tp&
281 	operator%=(_Tp& __a, const __max_size_type& __b) noexcept
282 	{ return (__a = static_cast<_Tp>(__a % __b)); }
283 
284       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
285 	friend constexpr _Tp&
286 	operator&=(_Tp& __a, const __max_size_type& __b) noexcept
287 	{ return (__a = static_cast<_Tp>(__a & __b)); }
288 
289       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
290 	friend constexpr _Tp&
291 	operator|=(_Tp& __a, const __max_size_type& __b) noexcept
292 	{ return (__a = static_cast<_Tp>(__a | __b)); }
293 
294       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
295 	friend constexpr _Tp&
296 	operator^=(_Tp& __a, const __max_size_type& __b) noexcept
297 	{ return (__a = static_cast<_Tp>(__a ^ __b)); }
298 
299       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
300 	friend constexpr _Tp&
301 	operator<<=(_Tp& __a, const __max_size_type& __b) noexcept
302 	{ return (__a = static_cast<_Tp>(__a << __b)); }
303 
304       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
305 	friend constexpr _Tp&
306 	operator>>=(_Tp& __a, const __max_size_type& __b) noexcept
307 	{ return (__a = static_cast<_Tp>(__a >> __b)); }
308 
309       friend constexpr __max_size_type
310       operator+(__max_size_type __l, const __max_size_type& __r) noexcept
311       {
312 	__l += __r;
313 	return __l;
314       }
315 
316       friend constexpr __max_size_type
317       operator-(__max_size_type __l, const __max_size_type& __r) noexcept
318       {
319 	__l -= __r;
320 	return __l;
321       }
322 
323       friend constexpr __max_size_type
324       operator*(__max_size_type __l, const __max_size_type& __r) noexcept
325       {
326 	__l *= __r;
327 	return __l;
328       }
329 
330       friend constexpr __max_size_type
331       operator/(__max_size_type __l, const __max_size_type& __r) noexcept
332       {
333 	__l /= __r;
334 	return __l;
335       }
336 
337       friend constexpr __max_size_type
338       operator%(__max_size_type __l, const __max_size_type& __r) noexcept
339       {
340 	__l %= __r;
341 	return __l;
342       }
343 
344       friend constexpr __max_size_type
345       operator<<(__max_size_type __l, const __max_size_type& __r) noexcept
346       {
347 	__l <<= __r;
348 	return __l;
349       }
350 
351       friend constexpr __max_size_type
352       operator>>(__max_size_type __l, const __max_size_type& __r) noexcept
353       {
354 	__l >>= __r;
355 	return __l;
356       }
357 
358       friend constexpr __max_size_type
359       operator&(__max_size_type __l, const __max_size_type& __r) noexcept
360       {
361 	__l &= __r;
362 	return __l;
363       }
364 
365       friend constexpr __max_size_type
366       operator|(__max_size_type __l, const __max_size_type& __r) noexcept
367       {
368 	__l |= __r;
369 	return __l;
370       }
371 
372       friend constexpr __max_size_type
373       operator^(__max_size_type __l, const __max_size_type& __r) noexcept
374       {
375 	__l ^= __r;
376 	return __l;
377       }
378 
379       friend constexpr bool
380       operator==(const __max_size_type& __l, const __max_size_type& __r) noexcept
381       { return __l._M_val == __r._M_val && __l._M_msb == __r._M_msb; }
382 
383 #if __cpp_lib_three_way_comparison
384       friend constexpr strong_ordering
385       operator<=>(const __max_size_type& __l, const __max_size_type& __r) noexcept
386       {
387 	if (__l._M_msb ^ __r._M_msb)
388 	  return __l._M_msb ? strong_ordering::greater : strong_ordering::less;
389 	else
390 	  return __l._M_val <=> __r._M_val;
391       }
392 #else
393       friend constexpr bool
394       operator!=(const __max_size_type& __l, const __max_size_type& __r) noexcept
395       { return !(__l == __r); }
396 
397       friend constexpr bool
398       operator<(const __max_size_type& __l, const __max_size_type& __r) noexcept
399       {
400 	if (__l._M_msb == __r._M_msb)
401 	  return __l._M_val < __r._M_val;
402 	else
403 	  return __r._M_msb;
404       }
405 
406       friend constexpr bool
407       operator>(const __max_size_type& __l, const __max_size_type& __r) noexcept
408       { return __r < __l; }
409 
410       friend constexpr bool
411       operator<=(const __max_size_type& __l, const __max_size_type& __r) noexcept
412       { return !(__l > __r); }
413 
414       friend constexpr bool
415       operator>=(const __max_size_type& __l, const __max_size_type& __r) noexcept
416       { return __r <= __l; }
417 #endif
418 
419 #if __SIZEOF_INT128__
420       __extension__
421       using __rep = unsigned __int128;
422 #else
423       using __rep = unsigned long long;
424 #endif
425       static constexpr size_t _S_rep_bits = sizeof(__rep) * __CHAR_BIT__;
426     private:
427       __rep _M_val = 0;
428       unsigned _M_msb:1 = 0;
429 
430       constexpr explicit
431       __max_size_type(__rep __val, int __msb) noexcept
432 	: _M_val(__val), _M_msb(__msb)
433       { }
434 
435       friend __max_diff_type;
436       friend std::numeric_limits<__max_size_type>;
437       friend std::numeric_limits<__max_diff_type>;
438     };
439 
440     class __max_diff_type
441     {
442     public:
443       __max_diff_type() = default;
444 
445       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
446 	constexpr
447 	__max_diff_type(_Tp __i) noexcept
448 	  : _M_rep(__i)
449 	{ }
450 
451       constexpr explicit
452       __max_diff_type(const __max_size_type& __d) noexcept
453 	: _M_rep(__d)
454       { }
455 
456       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
457 	constexpr explicit
458 	operator _Tp() const noexcept
459 	{ return static_cast<_Tp>(_M_rep); }
460 
461       constexpr explicit
462       operator bool() const noexcept
463       { return _M_rep != 0; }
464 
465       constexpr __max_diff_type
466       operator+() const noexcept
467       { return *this; }
468 
469       constexpr __max_diff_type
470       operator-() const noexcept
471       { return __max_diff_type(-_M_rep); }
472 
473       constexpr __max_diff_type
474       operator~() const noexcept
475       { return __max_diff_type(~_M_rep); }
476 
477       constexpr __max_diff_type&
478       operator++() noexcept
479       { return *this += 1; }
480 
481       constexpr __max_diff_type
482       operator++(int) noexcept
483       {
484 	auto __tmp = *this;
485 	++*this;
486 	return __tmp;
487       }
488 
489       constexpr __max_diff_type&
490       operator--() noexcept
491       { return *this -= 1; }
492 
493       constexpr __max_diff_type
494       operator--(int) noexcept
495       {
496 	auto __tmp = *this;
497 	--*this;
498 	return __tmp;
499       }
500 
501       constexpr __max_diff_type&
502       operator+=(const __max_diff_type& __r) noexcept
503       {
504 	_M_rep += __r._M_rep;
505 	return *this;
506       }
507 
508       constexpr __max_diff_type&
509       operator-=(const __max_diff_type& __r) noexcept
510       {
511 	_M_rep -= __r._M_rep;
512 	return *this;
513       }
514 
515       constexpr __max_diff_type&
516       operator*=(const __max_diff_type& __r) noexcept
517       {
518 	_M_rep *= __r._M_rep;
519 	return *this;
520       }
521 
522       constexpr __max_diff_type&
523       operator/=(const __max_diff_type& __r) noexcept
524       {
525 	__glibcxx_assert (__r != 0);
526 	const bool __neg = *this < 0;
527 	const bool __rneg = __r < 0;
528 	if (!__neg && !__rneg)
529 	  _M_rep = _M_rep / __r._M_rep;
530 	else if (__neg && __rneg)
531 	  _M_rep = -_M_rep / -__r._M_rep;
532 	else if (__neg && !__rneg)
533 	  _M_rep = -(-_M_rep / __r._M_rep);
534 	else
535 	  _M_rep = -(_M_rep / -__r._M_rep);
536 	return *this ;
537       }
538 
539       constexpr __max_diff_type&
540       operator%=(const __max_diff_type& __r) noexcept
541       {
542 	__glibcxx_assert (__r != 0);
543 	if (*this >= 0 && __r > 0)
544 	  _M_rep %= __r._M_rep;
545 	else
546 	  *this -= (*this / __r) * __r;
547 	return *this;
548       }
549 
550       constexpr __max_diff_type&
551       operator<<=(const __max_diff_type& __r) noexcept
552       {
553 	_M_rep.operator<<=(__r._M_rep);
554 	return *this;
555       }
556 
557       constexpr __max_diff_type&
558       operator>>=(const __max_diff_type& __r) noexcept
559       {
560 	// Arithmetic right shift.
561 	const auto __msb = _M_rep._M_msb;
562 	_M_rep >>= __r._M_rep;
563 	if (__msb)
564 	  _M_rep |= ~(__max_size_type(-1) >> __r._M_rep);
565 	return *this;
566       }
567 
568       constexpr __max_diff_type&
569       operator&=(const __max_diff_type& __r) noexcept
570       {
571 	_M_rep &= __r._M_rep;
572 	return *this;
573       }
574 
575       constexpr __max_diff_type&
576       operator|=(const __max_diff_type& __r) noexcept
577       {
578 	_M_rep |= __r._M_rep;
579 	return *this;
580       }
581 
582       constexpr __max_diff_type&
583       operator^=(const __max_diff_type& __r) noexcept
584       {
585 	_M_rep ^= __r._M_rep;
586 	return *this;
587       }
588 
589       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
590 	friend constexpr _Tp&
591 	operator+=(_Tp& __a, const __max_diff_type& __b) noexcept
592 	{ return (__a = static_cast<_Tp>(__a + __b)); }
593 
594       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
595 	friend constexpr _Tp&
596 	operator-=(_Tp& __a, const __max_diff_type& __b) noexcept
597 	{ return (__a = static_cast<_Tp>(__a - __b)); }
598 
599       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
600 	friend constexpr _Tp&
601 	operator*=(_Tp& __a, const __max_diff_type& __b) noexcept
602 	{ return (__a = static_cast<_Tp>(__a * __b)); }
603 
604       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
605 	friend constexpr _Tp&
606 	operator/=(_Tp& __a, const __max_diff_type& __b) noexcept
607 	{ return (__a = static_cast<_Tp>(__a / __b)); }
608 
609       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
610 	friend constexpr _Tp&
611 	operator%=(_Tp& __a, const __max_diff_type& __b) noexcept
612 	{ return (__a = static_cast<_Tp>(__a % __b)); }
613 
614       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
615 	friend constexpr _Tp&
616 	operator&=(_Tp& __a, const __max_diff_type& __b) noexcept
617 	{ return (__a = static_cast<_Tp>(__a & __b)); }
618 
619       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
620 	friend constexpr _Tp&
621 	operator|=(_Tp& __a, const __max_diff_type& __b) noexcept
622 	{ return (__a = static_cast<_Tp>(__a | __b)); }
623 
624       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
625 	friend constexpr _Tp&
626 	operator^=(_Tp& __a, const __max_diff_type& __b) noexcept
627 	{ return (__a = static_cast<_Tp>(__a ^ __b)); }
628 
629       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
630 	friend constexpr _Tp&
631 	operator<<=(_Tp& __a, const __max_diff_type& __b) noexcept
632 	{ return (__a = static_cast<_Tp>(__a << __b)); }
633 
634       template<typename _Tp> requires integral<_Tp> || __is_int128<_Tp>
635 	friend constexpr _Tp&
636 	operator>>=(_Tp& __a, const __max_diff_type& __b) noexcept
637 	{ return (__a = static_cast<_Tp>(__a >> __b)); }
638 
639       friend constexpr __max_diff_type
640       operator+(__max_diff_type __l, const __max_diff_type& __r) noexcept
641       {
642 	__l += __r;
643 	return __l;
644       }
645 
646       friend constexpr __max_diff_type
647       operator-(__max_diff_type __l, const __max_diff_type& __r) noexcept
648       {
649 	__l -= __r;
650 	return __l;
651       }
652 
653       friend constexpr __max_diff_type
654       operator*(__max_diff_type __l, const __max_diff_type& __r) noexcept
655       {
656 	__l *= __r;
657 	return __l;
658       }
659 
660       friend constexpr __max_diff_type
661       operator/(__max_diff_type __l, const __max_diff_type& __r) noexcept
662       {
663 	__l /= __r;
664 	return __l;
665       }
666 
667       friend constexpr __max_diff_type
668       operator%(__max_diff_type __l, const __max_diff_type& __r) noexcept
669       {
670 	__l %= __r;
671 	return __l;
672       }
673 
674       friend constexpr __max_diff_type
675       operator<<(__max_diff_type __l, const __max_diff_type& __r) noexcept
676       {
677 	__l <<= __r;
678 	return __l;
679       }
680 
681       friend constexpr __max_diff_type
682       operator>>(__max_diff_type __l, const __max_diff_type& __r) noexcept
683       {
684 	__l >>= __r;
685 	return __l;
686       }
687 
688       friend constexpr __max_diff_type
689       operator&(__max_diff_type __l, const __max_diff_type& __r) noexcept
690       {
691 	__l &= __r;
692 	return __l;
693       }
694 
695       friend constexpr __max_diff_type
696       operator|(__max_diff_type __l, const __max_diff_type& __r) noexcept
697       {
698 	__l |= __r;
699 	return __l;
700       }
701 
702       friend constexpr __max_diff_type
703       operator^(__max_diff_type __l, const __max_diff_type& __r) noexcept
704       {
705 	__l ^= __r;
706 	return __l;
707       }
708 
709       friend constexpr bool
710       operator==(const __max_diff_type& __l, const __max_diff_type& __r) noexcept
711       { return __l._M_rep == __r._M_rep; }
712 
713 #if __cpp_lib_three_way_comparison
714       constexpr strong_ordering
715       operator<=>(const __max_diff_type& __r) const noexcept
716       {
717 	const auto __lsign = _M_rep._M_msb;
718 	const auto __rsign = __r._M_rep._M_msb;
719 	if (__lsign ^ __rsign)
720 	  return __lsign ? strong_ordering::less : strong_ordering::greater;
721 	else
722 	  return _M_rep <=> __r._M_rep;
723       }
724 #else
725       friend constexpr bool
726       operator!=(const __max_diff_type& __l, const __max_diff_type& __r) noexcept
727       { return !(__l == __r); }
728 
729       constexpr bool
730       operator<(const __max_diff_type& __r) const noexcept
731       {
732 	const auto __lsign = _M_rep._M_msb;
733 	const auto __rsign = __r._M_rep._M_msb;
734 	if (__lsign ^ __rsign)
735 	  return __lsign;
736 	else
737 	  return _M_rep < __r._M_rep;
738       }
739 
740       friend constexpr bool
741       operator>(const __max_diff_type& __l, const __max_diff_type& __r) noexcept
742       { return __r < __l; }
743 
744       friend constexpr bool
745       operator<=(const __max_diff_type& __l, const __max_diff_type& __r) noexcept
746       { return !(__r < __l); }
747 
748       friend constexpr bool
749       operator>=(const __max_diff_type& __l, const __max_diff_type& __r) noexcept
750       { return !(__l < __r); }
751 #endif
752 
753     private:
754       __max_size_type _M_rep = 0;
755 
756       friend class __max_size_type;
757     };
758 
759     constexpr
760     __max_size_type::__max_size_type(const __max_diff_type& __d) noexcept
761       : __max_size_type(__d._M_rep)
762     { }
763 
764   } // namespace __detail
765 } // namespace ranges
766 
767   template<>
768     struct numeric_limits<ranges::__detail::__max_size_type>
769     {
770       using _Sp = ranges::__detail::__max_size_type;
771       static constexpr bool is_specialized = true;
772       static constexpr bool is_signed = false;
773       static constexpr bool is_integer = true;
774       static constexpr bool is_exact = true;
775       static constexpr int digits
776 	= __gnu_cxx::__int_traits<_Sp::__rep>::__digits + 1;
777       static constexpr int digits10
778 	= static_cast<int>(digits * numbers::ln2 / numbers::ln10);
779 
780       static constexpr _Sp
781       min() noexcept
782       { return 0; }
783 
784       static constexpr _Sp
785       max() noexcept
786       { return _Sp(static_cast<_Sp::__rep>(-1), 1); }
787 
788       static constexpr _Sp
789       lowest() noexcept
790       { return min(); }
791     };
792 
793   template<>
794     struct numeric_limits<ranges::__detail::__max_diff_type>
795     {
796       using _Dp = ranges::__detail::__max_diff_type;
797       using _Sp = ranges::__detail::__max_size_type;
798       static constexpr bool is_specialized = true;
799       static constexpr bool is_signed = true;
800       static constexpr bool is_integer = true;
801       static constexpr bool is_exact = true;
802       static constexpr int digits = numeric_limits<_Sp>::digits - 1;
803       static constexpr int digits10
804 	= static_cast<int>(digits * numbers::ln2 / numbers::ln10);
805 
806       static constexpr _Dp
807       min() noexcept
808       { return _Dp(_Sp(0, 1)); }
809 
810       static constexpr _Dp
811       max() noexcept
812       { return _Dp(_Sp(static_cast<_Sp::__rep>(-1), 0)); }
813 
814       static constexpr _Dp
815       lowest() noexcept
816       { return min(); }
817     };
818 
819 _GLIBCXX_END_NAMESPACE_VERSION
820 } // namespace
821 
822 #endif // C++20 && library concepts
823 #endif // _GLIBCXX_MAX_SIZE_TYPE_H
824