29
29
30
30
#include < __algorithm/for_each.h>
31
31
#include < __algorithm/move.h>
32
+ #include < __bit/bit_cast.h>
32
33
#include < __bit/bit_log2.h>
33
- #include < __bit/countl.h>
34
34
#include < __config>
35
+ #include < __cstddef/size_t.h>
35
36
#include < __functional/identity.h>
36
37
#include < __iterator/access.h>
37
38
#include < __iterator/distance.h>
44
45
#include < __type_traits/enable_if.h>
45
46
#include < __type_traits/invoke.h>
46
47
#include < __type_traits/is_assignable.h>
48
+ #include < __type_traits/is_enum.h>
47
49
#include < __type_traits/is_integral.h>
48
50
#include < __type_traits/is_unsigned.h>
49
51
#include < __type_traits/make_unsigned.h>
52
+ #include < __type_traits/void_t.h>
53
+ #include < __utility/declval.h>
50
54
#include < __utility/forward.h>
51
55
#include < __utility/integer_sequence.h>
52
56
#include < __utility/move.h>
@@ -298,6 +302,96 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __shift_to_unsigned(_Ip __n) {
298
302
return static_cast <make_unsigned_t <_Ip> >(__n ^ __min_value);
299
303
}
300
304
305
+ template <size_t _Size>
306
+ struct __unsigned_integer_of_size ;
307
+
308
+ template <>
309
+ struct __unsigned_integer_of_size <1 > {
310
+ using type _LIBCPP_NODEBUG = uint8_t ;
311
+ };
312
+
313
+ template <>
314
+ struct __unsigned_integer_of_size <2 > {
315
+ using type _LIBCPP_NODEBUG = uint16_t ;
316
+ };
317
+
318
+ template <>
319
+ struct __unsigned_integer_of_size <4 > {
320
+ using type _LIBCPP_NODEBUG = uint32_t ;
321
+ };
322
+
323
+ template <>
324
+ struct __unsigned_integer_of_size <8 > {
325
+ using type _LIBCPP_NODEBUG = uint64_t ;
326
+ };
327
+
328
+ # if _LIBCPP_HAS_INT128
329
+ template <>
330
+ struct __unsigned_integer_of_size <16 > {
331
+ using type _LIBCPP_NODEBUG = unsigned __int128;
332
+ };
333
+ # endif
334
+
335
+ template <size_t _Size>
336
+ using __unsigned_integer_of_size_t _LIBCPP_NODEBUG = typename __unsigned_integer_of_size<_Size>::type;
337
+
338
+ template <class _Sc >
339
+ using __unsigned_representation_for_t _LIBCPP_NODEBUG = __unsigned_integer_of_size_t <sizeof (_Sc)>;
340
+
341
+ // The function `__to_ordered_integral` is defined for integers and IEEE 754 floating-point numbers.
342
+ // Returns an integer representation such that for any `x` and `y` such that `x < y`, the expression
343
+ // `__to_ordered_integral(x) < __to_ordered_integral(y)` is true, where `x`, `y` are integers or IEEE 754 floats.
344
+ template <class _Integral , enable_if_t < is_integral<_Integral>::value, int > = 0 >
345
+ _LIBCPP_HIDE_FROM_ABI constexpr auto __to_ordered_integral (_Integral __n) {
346
+ return __n;
347
+ }
348
+
349
+ // An overload for IEEE 754 floating-point numbers
350
+
351
+ // For the floats conforming to IEEE 754 (IEC 559) standard, we know that:
352
+ // 1. The bit representation of positive floats directly reflects their order:
353
+ // When comparing floats by magnitude, the number with the larger exponent is greater, and if the exponents are
354
+ // equal, the one with the larger mantissa is greater.
355
+ // 2. The bit representation of negative floats reflects their reverse order (for the same reasons).
356
+ // 3. The most significant bit (sign bit) is zero for positive floats and one for negative floats. Therefore, in the raw
357
+ // bit representation, any negative number will be greater than any positive number.
358
+
359
+ // The only exception from this rule is `NaN`, which is unordered by definition.
360
+
361
+ // Based on the above, to obtain correctly ordered integral representation of floating-point numbers, we need to:
362
+ // 1. Invert the bit representation (including the sign bit) of negative floats to switch from reverse order to direct
363
+ // order;
364
+ // 2. Invert the sign bit for positive floats.
365
+
366
+ // Thus, in final integral representation, we have reversed the order for negative floats and made all negative floats
367
+ // smaller than all positive numbers (by inverting the sign bit).
368
+ template <class _Floating , enable_if_t < numeric_limits<_Floating>::is_iec559, int > = 0 >
369
+ _LIBCPP_HIDE_FROM_ABI constexpr auto __to_ordered_integral (_Floating __f) {
370
+ using __integral_type = __unsigned_representation_for_t <_Floating>;
371
+ constexpr auto __bit_count = std::numeric_limits<__integral_type>::digits;
372
+ constexpr auto __sign_bit_mask = static_cast <__integral_type>(__integral_type{1 } << (__bit_count - 1 ));
373
+
374
+ const auto __u = std::__bit_cast<__integral_type>(__f);
375
+
376
+ return static_cast <__integral_type>(__u & __sign_bit_mask ? ~__u : __u ^ __sign_bit_mask);
377
+ }
378
+
379
+ // There may exist user-defined comparison for enum, so we cannot compare enums just like integers.
380
+ template <class _Enum , enable_if_t < is_enum<_Enum>::value, int > = 0 >
381
+ _LIBCPP_HIDE_FROM_ABI constexpr auto __to_ordered_integral (_Enum __e) = delete;
382
+
383
+ // `long double` varies significantly across platforms and compilers, making it practically
384
+ // impossible to determine its actual bit width for conversion to an ordered integer.
385
+ inline _LIBCPP_HIDE_FROM_ABI constexpr auto __to_ordered_integral (long double ) = delete;
386
+
387
+ template <class _Tp , class = void >
388
+ inline const bool __is_ordered_integer_representable_v = false ;
389
+
390
+ template <class _Tp >
391
+ inline const bool
392
+ __is_ordered_integer_representable_v<_Tp, __void_t <decltype(std::__to_ordered_integral(std::declval<_Tp>()))>> =
393
+ true ;
394
+
301
395
struct __low_byte_fn {
302
396
template <class _Ip >
303
397
_LIBCPP_HIDE_FROM_ABI constexpr uint8_t operator ()(_Ip __integer) const {
@@ -314,7 +408,9 @@ __radix_sort(_RandomAccessIterator1 __first,
314
408
_RandomAccessIterator2 __buffer,
315
409
_Map __map,
316
410
_Radix __radix) {
317
- auto __map_to_unsigned = [__map = std::move (__map)](const auto & __x) { return std::__shift_to_unsigned (__map (__x)); };
411
+ auto __map_to_unsigned = [__map = std::move (__map)](const auto & __x) {
412
+ return std::__shift_to_unsigned (__map (std::__to_ordered_integral (__x)));
413
+ };
318
414
std::__radix_sort_impl (__first, __last, __buffer, __map_to_unsigned, __radix);
319
415
}
320
416
0 commit comments