@@ -2694,11 +2694,6 @@ unicode_fromformat_write_wcstr(_PyUnicodeWriter *writer, const wchar_t *str,
26942694#define F_SIZE 3
26952695#define F_PTRDIFF 4
26962696#define F_INTMAX 5
2697- static const char * const formats [] = {"%d" , "%ld" , "%lld" , "%zd" , "%td" , "%jd" };
2698- static const char * const formats_o [] = {"%o" , "%lo" , "%llo" , "%zo" , "%to" , "%jo" };
2699- static const char * const formats_u [] = {"%u" , "%lu" , "%llu" , "%zu" , "%tu" , "%ju" };
2700- static const char * const formats_x [] = {"%x" , "%lx" , "%llx" , "%zx" , "%tx" , "%jx" };
2701- static const char * const formats_X [] = {"%X" , "%lX" , "%llX" , "%zX" , "%tX" , "%jX" };
27022697
27032698static const char *
27042699unicode_fromformat_arg (_PyUnicodeWriter * writer ,
@@ -2840,47 +2835,44 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
28402835 case 'd' : case 'i' :
28412836 case 'o' : case 'u' : case 'x' : case 'X' :
28422837 {
2843- /* used by sprintf */
28442838 char buffer [MAX_INTMAX_CHARS ];
2845- const char * fmt = NULL ;
2846- switch (* f ) {
2847- case 'o' : fmt = formats_o [sizemod ]; break ;
2848- case 'u' : fmt = formats_u [sizemod ]; break ;
2849- case 'x' : fmt = formats_x [sizemod ]; break ;
2850- case 'X' : fmt = formats_X [sizemod ]; break ;
2851- default : fmt = formats [sizemod ]; break ;
2852- }
2853- int issigned = (* f == 'd' || * f == 'i' );
2839+
2840+ // Fill buffer using sprinf, with one of many possible format
2841+ // strings, like "%llX" for `long long` in hexadecimal.
2842+ // The type/size is in `sizemod`; the format is in `*f`.
2843+
2844+ // Use macros with nested switches to keep the sprintf format strings
2845+ // as compile-time literals, avoiding warnings and maybe allowing
2846+ // optimizations.
2847+
2848+ // `SPRINT` macro does one sprintf
2849+ // Example usage: SPRINT("l", "X", unsigned long) expands to
2850+ // sprintf(buffer, "%" "l" "X", va_arg(*vargs, unsigned long))
2851+ #define SPRINT (SIZE_SPEC , FMT_CHAR , TYPE ) \
2852+ sprintf(buffer, "%" SIZE_SPEC FMT_CHAR, va_arg(*vargs, TYPE))
2853+
2854+ // One inner switch to handle all format variants
2855+ #define DO_SPRINTS (SIZE_SPEC , SIGNED_TYPE , UNSIGNED_TYPE ) \
2856+ switch (*f) { \
2857+ case 'o': len = SPRINT(SIZE_SPEC, "o", UNSIGNED_TYPE); break; \
2858+ case 'u': len = SPRINT(SIZE_SPEC, "u", UNSIGNED_TYPE); break; \
2859+ case 'x': len = SPRINT(SIZE_SPEC, "x", UNSIGNED_TYPE); break; \
2860+ case 'X': len = SPRINT(SIZE_SPEC, "X", UNSIGNED_TYPE); break; \
2861+ default: len = SPRINT(SIZE_SPEC, "d", SIGNED_TYPE); break; \
2862+ }
2863+
2864+ // Outer switch to handle all the sizes/types
28542865 switch (sizemod ) {
2855- case F_LONG :
2856- len = issigned ?
2857- sprintf (buffer , fmt , va_arg (* vargs , long )) :
2858- sprintf (buffer , fmt , va_arg (* vargs , unsigned long ));
2859- break ;
2860- case F_LONGLONG :
2861- len = issigned ?
2862- sprintf (buffer , fmt , va_arg (* vargs , long long )) :
2863- sprintf (buffer , fmt , va_arg (* vargs , unsigned long long));
2864- break ;
2865- case F_SIZE :
2866- len = issigned ?
2867- sprintf (buffer , fmt , va_arg (* vargs , Py_ssize_t )) :
2868- sprintf (buffer , fmt , va_arg (* vargs , size_t ));
2869- break ;
2870- case F_PTRDIFF :
2871- len = sprintf (buffer , fmt , va_arg (* vargs , ptrdiff_t ));
2872- break ;
2873- case F_INTMAX :
2874- len = issigned ?
2875- sprintf (buffer , fmt , va_arg (* vargs , intmax_t )) :
2876- sprintf (buffer , fmt , va_arg (* vargs , uintmax_t ));
2877- break ;
2878- default :
2879- len = issigned ?
2880- sprintf (buffer , fmt , va_arg (* vargs , int )) :
2881- sprintf (buffer , fmt , va_arg (* vargs , unsigned int ));
2882- break ;
2866+ case F_LONG : DO_SPRINTS ("l" , long , unsigned long ); break ;
2867+ case F_LONGLONG : DO_SPRINTS ("ll" , long long , unsigned long long); break ;
2868+ case F_SIZE : DO_SPRINTS ("z" , Py_ssize_t , size_t ); break ;
2869+ case F_PTRDIFF : DO_SPRINTS ("t" , ptrdiff_t , ptrdiff_t ); break ;
2870+ case F_INTMAX : DO_SPRINTS ("j" , intmax_t , uintmax_t ); break ;
2871+ default : DO_SPRINTS ("" , int , unsigned int ); break ;
28832872 }
2873+ #undef SPRINT
2874+ #undef DO_SPRINTS
2875+
28842876 assert (len >= 0 );
28852877
28862878 int sign = (buffer [0 ] == '-' );
0 commit comments