commit eaf8f8428297bd8f879f0e84b2f67f0d23673489 parent 61cfc151f29bd08d236f024a56b3a4e0b4a3f821 Author: Michael Savage <mikejsavage@gmail.com> Date: Thu Aug 24 19:49:00 +0100 ggformat updates Diffstat:
ggformat.cc | | | 77 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
ggformat.h | | | 42 | ++++++++++++++++++++---------------------- |
diff --git a/ggformat.cc b/ggformat.cc @@ -50,6 +50,7 @@ void format( FormatBuffer * fb, double x, const FormatOpts & opts ) { int precision = opts.precision != -1 ? opts.precision : 5; if( opts.plus_sign ) fmt += "+"; if( opts.left_align ) fmt += "-"; + if( opts.zero_pad ) fmt += "0"; if( opts.width != -1 ) fmt += opts.width + 1 + precision; fmt += "."; fmt += precision; @@ -94,30 +95,35 @@ static void int_helper( FormatBuffer * fb, const char * fmt_decimal, const T & x fmt += "x"; } else if( opts.number_format == FormatOpts::BINARY ) { - ASSERT( !"not implemented" ); + fmt += "s"; + char binary[ sizeof( x ) * 8 + 1 ]; + binary[ sizeof( x ) * 8 ] = '\0'; + + for( size_t i = 0; i < sizeof( x ) * 8; i++ ) { + // this is UB for signed types, but who cares? + T bit = x & ( T( 1 ) << ( sizeof( x ) * 8 - i - 1 ) ); + binary[ i ] = bit == 0 ? '0' : '1'; + } + + format_helper( fb, fmt, binary ); + return; } format_helper( fb, fmt, x ); } -void format( FormatBuffer * fb, long long x, const FormatOpts & opts ) { - int_helper( fb, "d", x, opts ); -} - -void format( FormatBuffer * fb, unsigned long long x, const FormatOpts & opts ) { - int_helper( fb, "u", x, opts ); -} - #define INT_OVERLOADS( T ) \ - void format( FormatBuffer * fb, T x, const FormatOpts & opts ) { \ - format( fb, ( long long ) x, opts ); \ + void format( FormatBuffer * fb, signed T x, const FormatOpts & opts ) { \ + int_helper( fb, "d", x, opts ); \ } \ void format( FormatBuffer * fb, unsigned T x, const FormatOpts & opts ) { \ - format( fb, ( unsigned long long ) x, opts ); \ + int_helper( fb, "u", x, opts ); \ } +INT_OVERLOADS( char ) INT_OVERLOADS( short ) INT_OVERLOADS( int ) INT_OVERLOADS( long ) +INT_OVERLOADS( long long ) #undef INT_OVERLOADS @@ -206,15 +212,50 @@ static bool strchridx( const char * haystack, char needle, size_t * idx, size_t } bool ggformat_find( const char * str, size_t * start, size_t * one_past_end ) { - bool has_open = strchridx( str, '{', start ); - if( !has_open ) return false; - bool has_close = strchridx( str, '}', one_past_end, *start ); - ASSERT( has_close ); - return true; + size_t open_idx; + bool has_open = strchridx( str, '{', &open_idx ); + if( has_open && str[ open_idx + 1 ] == '{' ) { + has_open = false; + } + if( !has_open ) open_idx = 0; + + size_t close_idx; + bool has_close = strchridx( str, '}', &close_idx, open_idx ); + if( has_close && str[ close_idx + 1 ] == '}' ) { + has_close = false; + } + + if( has_open ) { + ASSERT( has_close ); + ASSERT( open_idx < close_idx ); + + *start = open_idx; + *one_past_end = close_idx; + + return true; + } + + ASSERT( !has_close ); + return false; +} + +void ggformat_literals( FormatBuffer * fb, const char * literals, size_t len ) { + size_t copied_len = 0; + for( size_t i = 0; i < len; i++ ) { + if( literals[ i ] == '{' || literals[ i ] == '}' ) { + i++; + } + if( fb->len + copied_len < fb->capacity ) { + fb->buf[ fb->len + copied_len ] = literals[ i ]; + } + copied_len++; + } + fb->len += copied_len; + fb->buf[ fb->len < fb->capacity - 1 ? fb->len : fb->capacity - 1 ] = '\0'; } void ggformat_impl( FormatBuffer * fb, const char * fmt ) { size_t ignored; ASSERT( !ggformat_find( fmt, &ignored, &ignored ) ); - format( fb, fmt ); + ggformat_literals( fb, fmt, strlen( fmt ) ); } diff --git a/ggformat.h b/ggformat.h @@ -1,23 +1,20 @@ #pragma once #include <stdio.h> -#include <stddef.h> - -/* - * a type safe replacement for printf - */ +#include <stdlib.h> /* * prototypes of the functions you should be calling */ + template< typename... Rest > size_t ggformat( char * buf, size_t len, const char * fmt, Rest... rest ); template< typename... Rest > -void ggprint_to_file( FILE * file, const char * fmt, Rest... rest ); +bool ggprint_to_file( FILE * file, const char * fmt, Rest... rest ); template< typename... Rest > -void ggprint( const char * fmt, Rest... rest ); +bool ggprint( const char * fmt, Rest... rest ); /* * structures and functions used for formatting specific data types @@ -50,10 +47,12 @@ struct FormatBuffer { * format implementations for primitive types */ +void format( FormatBuffer * fb, signed char x, const FormatOpts & opts ); void format( FormatBuffer * fb, short x, const FormatOpts & opts ); void format( FormatBuffer * fb, int x, const FormatOpts & opts ); void format( FormatBuffer * fb, long x, const FormatOpts & opts ); void format( FormatBuffer * fb, long long x, const FormatOpts & opts ); +void format( FormatBuffer * fb, unsigned char x, const FormatOpts & opts ); void format( FormatBuffer * fb, unsigned short x, const FormatOpts & opts ); void format( FormatBuffer * fb, unsigned int x, const FormatOpts & opts ); void format( FormatBuffer * fb, unsigned long x, const FormatOpts & opts ); @@ -74,6 +73,7 @@ void format( FormatBuffer * fb, const char * x, const FormatOpts & opts = Format FormatOpts parse_formatopts( const char * fmt, size_t len ); void ggformat_impl( FormatBuffer * fb, const char * fmt ); bool ggformat_find( const char * str, size_t * start, size_t * one_past_end ); +void ggformat_literals( FormatBuffer * fb, const char * literals, size_t len ); PRAGMA_DISABLE_OPTIMISATIONS(); @@ -83,12 +83,7 @@ void ggformat_impl( FormatBuffer * fb, const char * fmt, const T & first, Rest.. bool has_fmt = ggformat_find( fmt, &start, &one_past_end ); ASSERT( has_fmt ); - if( fb->len < fb->capacity ) { - size_t remaining = fb->capacity - fb->len; - size_t to_copy = min( remaining, start + 1 ); - snprintf( fb->buf + fb->len, to_copy, "%s", fmt ); - } - fb->len += start; + ggformat_literals( fb, fmt, start ); FormatOpts opts = parse_formatopts( fmt + start + 1, one_past_end - start - 1 ); format( fb, first, opts ); @@ -104,26 +99,29 @@ size_t ggformat( char * buf, size_t len, const char * fmt, Rest... rest ) { } template< typename... Rest > -void ggprint_to_file( FILE * file, const char * fmt, Rest... rest ) { +bool ggprint_to_file( FILE * file, const char * fmt, Rest... rest ) { char buf[ 4096 ]; FormatBuffer fb( buf, sizeof( buf ) ); ggformat_impl( &fb, fmt, rest... ); if( fb.len < fb.capacity ) { - fprintf( file, "%s", buf ); - return; + size_t written = fwrite( buf, 1, fb.len, file ); + return written == fb.len; } - char * new_buf = new char[ fb.len + 1 ](); - FormatBuffer new_fb( new_buf, fb.len + 1 ); + char * large_buf = ( char * ) malloc( fb.len + 1 ); + ASSERT( large_buf != NULL ); + FormatBuffer new_fb( large_buf, fb.len + 1 ); ggformat_impl( &new_fb, fmt, rest... ); - fprintf( file, "%s", new_buf ); - delete[] new_buf; + size_t written = fwrite( large_buf, 1, fb.len, file ); + free( large_buf ); + + return written == fb.len; } template< typename... Rest > -void ggprint( const char * fmt, Rest... rest ) { - ggprint_to_file( stdout, fmt, rest... ); +bool ggprint( const char * fmt, Rest... rest ) { + return ggprint_to_file( stdout, fmt, rest... ); } PRAGMA_ENABLE_OPTIMISATIONS();