From 3a3c645696c9986ecd655300485938323e937b80 Mon Sep 17 00:00:00 2001 From: Cazadorro Date: Wed, 18 Mar 2026 16:23:20 -0500 Subject: [PATCH 1/9] converted formafractional_part_rounding_thresholds to use an array of u32s instead of a unicode literal character array for compatibliity with CUDA and non CUDA platforms --- include/fmt/format.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index b358f0425fa2..bf6745ae9066 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3208,6 +3208,13 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs, format_hexfloat(static_cast(value), specs, buf); } +// pre C++23 does not allow static constexpr inside of constexpr functions +// so we must declare this outside of fractional_part_rounding_thresholds +static constexpr uint32_t utf8_raw_rounding_thresholds[8] = { + 0x9999999au, 0x828f5c29u, 0x80418938u, 0x80068db9, + 0x8000a7c6u, 0x800010c7u, 0x800001aeu, 0x8000002bu +}; + constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // For checking rounding thresholds. // The kth entry is chosen to be the smallest integer such that the @@ -3215,8 +3222,8 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // It is equal to ceil(2^31 + 2^32/10^(k + 1)). // These are stored in a string literal because we cannot have static arrays // in constexpr functions and non-static ones are poorly optimized. - return U"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7" - U"\x800001ae\x8000002b"[index]; + + return utf8_raw_rounding_thresholds[index]; } template From 9661f8934645120cfe824a106c1291f6230f0213 Mon Sep 17 00:00:00 2001 From: Cazadorro Date: Tue, 24 Mar 2026 18:15:34 -0500 Subject: [PATCH 2/9] fixed clang format issue --- include/fmt/format.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index bf6745ae9066..270fa816dc5d 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3211,9 +3211,8 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs, // pre C++23 does not allow static constexpr inside of constexpr functions // so we must declare this outside of fractional_part_rounding_thresholds static constexpr uint32_t utf8_raw_rounding_thresholds[8] = { - 0x9999999au, 0x828f5c29u, 0x80418938u, 0x80068db9, - 0x8000a7c6u, 0x800010c7u, 0x800001aeu, 0x8000002bu -}; + 0x9999999au, 0x828f5c29u, 0x80418938u, 0x80068db9, + 0x8000a7c6u, 0x800010c7u, 0x800001aeu, 0x8000002bu}; constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // For checking rounding thresholds. From 432f5899e30e536404f52e49d27d2f9f2802d00a Mon Sep 17 00:00:00 2001 From: Cazadorro Date: Sat, 28 Mar 2026 14:12:14 -0500 Subject: [PATCH 3/9] changed naming of rounding thresholds, and changed static constexpr declaration of thresholds to inline constexpr, this should mean same address for every translation unit see: https://stackoverflow.com/a/57407675 --- include/fmt/format.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 9a4dbb1db423..f6712bc63afc 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3151,7 +3151,7 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs, // pre C++23 does not allow static constexpr inside of constexpr functions // so we must declare this outside of fractional_part_rounding_thresholds -static constexpr uint32_t utf8_raw_rounding_thresholds[8] = { +inline constexpr uint32_t rounding_thresholds[8] = { 0x9999999au, 0x828f5c29u, 0x80418938u, 0x80068db9, 0x8000a7c6u, 0x800010c7u, 0x800001aeu, 0x8000002bu}; @@ -3163,7 +3163,7 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // These are stored in a string literal because we cannot have static arrays // in constexpr functions and non-static ones are poorly optimized. - return utf8_raw_rounding_thresholds[index]; + return rounding_thresholds[index]; } template From dedbeeebb037f7bae86d8b9874a02669d70e3951 Mon Sep 17 00:00:00 2001 From: Cazadorro Date: Sat, 28 Mar 2026 23:16:40 -0500 Subject: [PATCH 4/9] Removed inline constexpr as it doesn't work in C++11, instead relying on the compiler cannonizing char litteral arrays in order to avoid duplicating the array definition per translation unit --- include/fmt/format.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index f6712bc63afc..de9f6ebf2097 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3149,12 +3149,6 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs, format_hexfloat(static_cast(value), specs, buf); } -// pre C++23 does not allow static constexpr inside of constexpr functions -// so we must declare this outside of fractional_part_rounding_thresholds -inline constexpr uint32_t rounding_thresholds[8] = { - 0x9999999au, 0x828f5c29u, 0x80418938u, 0x80068db9, - 0x8000a7c6u, 0x800010c7u, 0x800001aeu, 0x8000002bu}; - constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // For checking rounding thresholds. // The kth entry is chosen to be the smallest integer such that the @@ -3163,7 +3157,27 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // These are stored in a string literal because we cannot have static arrays // in constexpr functions and non-static ones are poorly optimized. - return rounding_thresholds[index]; + // while in C++23 we can use static constexpr, and in c++17 we can use out of + // function defintion of inline constexpr, in C++11 we have to rely on string + // literals in order to avoid duplicating constant definitions across + // translation units. We take the following uint32 array definition: + // {0x9999999au, 0x828f5c29u, 0x80418938u, 0x80068db9, + // 0x8000a7c6u, 0x800010c7u, 0x800001aeu, 0x8000002bu}; + // and convert that into a series of char hexidecimal literals in a char array: + // "\x99\x99\x99\x9a \x82\x8f\x5c\x29 \x80\x41\x89\x38 \x80\x06\x8d\xb9 + // \x80\x00\xa7\xc6 \x80\x00\x10\xc7 \x80\x00\x01\xae \x80\x00\x00\x2b" + // Then we split this up into four seperate arrays of bytes, so the bytes can + // be properly recombined into endian-correct uint32_t. + + + uint32_t byte_3 = static_cast("\x99\x82\x80\x80\x80\x80\x80\x80"[index]); + uint32_t byte_2 = static_cast("\x99\x8f\x41\x06\x00\x00\x00\x00"[index]); + uint32_t byte_1 = static_cast("\x99\x5c\x89\x8d\xa7\x10\x01\x00"[index]); + uint32_t byte_0 = static_cast("\x9a\x29\x38\xb9\xc6\xc7\xae\x2b"[index]); + + //recombine as uint32, this should eliminate endian issues, as now we are shifting + //btyes as uint32 which should match platform endian. + return byte_3 << 24u | byte_2 << 16u | byte_1 << 8u | byte_0; } template From 38d164d45299d6f2c18fa6c9528f5ecf88cf8af6 Mon Sep 17 00:00:00 2001 From: Cazadorro Date: Sat, 28 Mar 2026 23:25:10 -0500 Subject: [PATCH 5/9] fixed spelling errors in recent comments --- include/fmt/format.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index de9f6ebf2097..1c3ea9358c4e 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3158,7 +3158,7 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // in constexpr functions and non-static ones are poorly optimized. // while in C++23 we can use static constexpr, and in c++17 we can use out of - // function defintion of inline constexpr, in C++11 we have to rely on string + // function definition of inline constexpr, in C++11 we have to rely on string // literals in order to avoid duplicating constant definitions across // translation units. We take the following uint32 array definition: // {0x9999999au, 0x828f5c29u, 0x80418938u, 0x80068db9, @@ -3166,7 +3166,7 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // and convert that into a series of char hexidecimal literals in a char array: // "\x99\x99\x99\x9a \x82\x8f\x5c\x29 \x80\x41\x89\x38 \x80\x06\x8d\xb9 // \x80\x00\xa7\xc6 \x80\x00\x10\xc7 \x80\x00\x01\xae \x80\x00\x00\x2b" - // Then we split this up into four seperate arrays of bytes, so the bytes can + // Then we split this up into four separate arrays of bytes, so the bytes can // be properly recombined into endian-correct uint32_t. @@ -3176,7 +3176,7 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { uint32_t byte_0 = static_cast("\x9a\x29\x38\xb9\xc6\xc7\xae\x2b"[index]); //recombine as uint32, this should eliminate endian issues, as now we are shifting - //btyes as uint32 which should match platform endian. + //bytes as uint32 which should match platform endian. return byte_3 << 24u | byte_2 << 16u | byte_1 << 8u | byte_0; } From 60fec1064bee2c278e33c83b80015dd80bd3e049 Mon Sep 17 00:00:00 2001 From: Cazadorro Date: Sat, 28 Mar 2026 23:28:22 -0500 Subject: [PATCH 6/9] Fixed minor formatting issues in comments, added const to local byte_x variables in fractional_part_rounding_thresholds, and applied clang format to function --- include/fmt/format.h | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 1c3ea9358c4e..c93d85acf4c2 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3163,20 +3163,24 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // translation units. We take the following uint32 array definition: // {0x9999999au, 0x828f5c29u, 0x80418938u, 0x80068db9, // 0x8000a7c6u, 0x800010c7u, 0x800001aeu, 0x8000002bu}; - // and convert that into a series of char hexidecimal literals in a char array: - // "\x99\x99\x99\x9a \x82\x8f\x5c\x29 \x80\x41\x89\x38 \x80\x06\x8d\xb9 - // \x80\x00\xa7\xc6 \x80\x00\x10\xc7 \x80\x00\x01\xae \x80\x00\x00\x2b" + // and convert that into a series of char hexidecimal literals in a char + // array: + // "\x99\x99\x99\x9a \x82\x8f\x5c\x29 \x80\x41\x89\x38 \x80\x06\x8d\xb9 + // \x80\x00\xa7\xc6 \x80\x00\x10\xc7 \x80\x00\x01\xae \x80\x00\x00\x2b" // Then we split this up into four separate arrays of bytes, so the bytes can // be properly recombined into endian-correct uint32_t. - - uint32_t byte_3 = static_cast("\x99\x82\x80\x80\x80\x80\x80\x80"[index]); - uint32_t byte_2 = static_cast("\x99\x8f\x41\x06\x00\x00\x00\x00"[index]); - uint32_t byte_1 = static_cast("\x99\x5c\x89\x8d\xa7\x10\x01\x00"[index]); - uint32_t byte_0 = static_cast("\x9a\x29\x38\xb9\xc6\xc7\xae\x2b"[index]); - - //recombine as uint32, this should eliminate endian issues, as now we are shifting - //bytes as uint32 which should match platform endian. + const uint32_t byte_3 = + static_cast("\x99\x82\x80\x80\x80\x80\x80\x80"[index]); + const uint32_t byte_2 = + static_cast("\x99\x8f\x41\x06\x00\x00\x00\x00"[index]); + const uint32_t byte_1 = + static_cast("\x99\x5c\x89\x8d\xa7\x10\x01\x00"[index]); + const uint32_t byte_0 = + static_cast("\x9a\x29\x38\xb9\xc6\xc7\xae\x2b"[index]); + + // recombine as uint32, this should eliminate endian issues, as now we are + // shifting bytes as uint32 which should match platform endian. return byte_3 << 24u | byte_2 << 16u | byte_1 << 8u | byte_0; } From 06465e1e96e2e2056cd42f6470f05f66e5e30f6d Mon Sep 17 00:00:00 2001 From: Cazadorro Date: Thu, 2 Apr 2026 18:44:04 -0500 Subject: [PATCH 7/9] using char16 literals instead of chars for recombining --- include/fmt/format.h | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index c93d85acf4c2..a51cb7987ded 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3162,26 +3162,22 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // literals in order to avoid duplicating constant definitions across // translation units. We take the following uint32 array definition: // {0x9999999au, 0x828f5c29u, 0x80418938u, 0x80068db9, - // 0x8000a7c6u, 0x800010c7u, 0x800001aeu, 0x8000002bu}; - // and convert that into a series of char hexidecimal literals in a char + // 0x8000a7c6u, 0x800010c7u, 0x800001aeu, 0x8000002b}; + // and convert that into a series of char hexidecimal literals in a char16_t // array: - // "\x99\x99\x99\x9a \x82\x8f\x5c\x29 \x80\x41\x89\x38 \x80\x06\x8d\xb9 - // \x80\x00\xa7\xc6 \x80\x00\x10\xc7 \x80\x00\x01\xae \x80\x00\x00\x2b" - // Then we split this up into four separate arrays of bytes, so the bytes can - // be properly recombined into endian-correct uint32_t. - - const uint32_t byte_3 = - static_cast("\x99\x82\x80\x80\x80\x80\x80\x80"[index]); - const uint32_t byte_2 = - static_cast("\x99\x8f\x41\x06\x00\x00\x00\x00"[index]); - const uint32_t byte_1 = - static_cast("\x99\x5c\x89\x8d\xa7\x10\x01\x00"[index]); - const uint32_t byte_0 = - static_cast("\x9a\x29\x38\xb9\xc6\xc7\xae\x2b"[index]); - - // recombine as uint32, this should eliminate endian issues, as now we are - // shifting bytes as uint32 which should match platform endian. - return byte_3 << 24u | byte_2 << 16u | byte_1 << 8u | byte_0; + // "\x9999\x999a \x828f\x5c29 \x8041\x8938 \x8006\x8db9 + // \x8000\xa7c6 \x8000\x10c7 \x8000\x01ae \x8000\x002b"; + // Then we split this up into two separate arrays of char16_ts, so they can + // be properly recombined into uint32_t. + + const uint32_t high_bytes = static_cast( + u"\x9999\x828f\x8041\x8006" + u"\x8000\x8000\x8000\x8000"[index]); + const uint32_t low_bytes = static_cast( + u"\x999a\x5c29\x8938\x8db9" + u"\xa7c6\x10c7\x01ae\x002b"[index]); + + return high_bytes << 16u | low_bytes; } template From 629478e673168da890a6f86fbbbe8377bac0b66a Mon Sep 17 00:00:00 2001 From: Cazadorro Date: Fri, 3 Apr 2026 21:56:15 -0500 Subject: [PATCH 8/9] combined fractalfractional_part_rounding_thresholds into a single statement for c++11 compatibility --- include/fmt/format.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index d2eecf3eb9de..d7180588f509 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3175,14 +3175,11 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // Then we split this up into two separate arrays of char16_ts, so they can // be properly recombined into uint32_t. - const uint32_t high_bytes = static_cast( - u"\x9999\x828f\x8041\x8006" - u"\x8000\x8000\x8000\x8000"[index]); - const uint32_t low_bytes = static_cast( - u"\x999a\x5c29\x8938\x8db9" - u"\xa7c6\x10c7\x01ae\x002b"[index]); - - return high_bytes << 16u | low_bytes; + return static_cast( + u"\x9999\x828f\x8041\x8006\x8000\x8000\x8000\x8000"[index]) + << 16u | + static_cast( + u"\x999a\x5c29\x8938\x8db9\xa7c6\x10c7\x01ae\x002b"[index]); } template From a26db574a2bd2bc0e5b8184150deb199b9314f00 Mon Sep 17 00:00:00 2001 From: Cazadorro Date: Sun, 5 Apr 2026 13:06:51 -0500 Subject: [PATCH 9/9] should get rid of the implicit conversion warning due to u16's always converting to i32 when any operation applied --- include/fmt/format.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index d7180588f509..68c3f76b282f 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3175,10 +3175,10 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // Then we split this up into two separate arrays of char16_ts, so they can // be properly recombined into uint32_t. - return static_cast( + return static_cast( u"\x9999\x828f\x8041\x8006\x8000\x8000\x8000\x8000"[index]) << 16u | - static_cast( + static_cast( u"\x999a\x5c29\x8938\x8db9\xa7c6\x10c7\x01ae\x002b"[index]); }