Fix stdlib assertion

The assertion checks if an element has been added to vector.  Since we
are merely manipulating the allocated data, the number of elements does
not change and the assertion check fails.  Using the pointer to the
allocated data is a cleaner/clearer way of accomplishing this
This commit is contained in:
Seth Hillbrand 2023-10-10 10:06:29 -07:00
parent e55989120e
commit 6c91a3022e
2 changed files with 49 additions and 28 deletions

View File

@ -48,35 +48,17 @@
static int vprint( std::string* result, const char* format, va_list ap )
{
char msg[512];
// This function can call vsnprintf twice.
// But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
// va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
// see: www.cplusplus.com/reference/cstdio/vsnprintf
// we make a copy of va_list ap for the second call, if happens
va_list tmp;
va_copy( tmp, ap );
size_t len = vsnprintf( nullptr, 0, format, tmp );
va_end( tmp );
size_t len = vsnprintf( msg, sizeof(msg), format, ap );
// Resize the output to hold the required data
size_t size = result->size();
result->resize( size + len );
if( len < sizeof(msg) ) // the output fit into msg
{
result->append( msg, msg + len );
}
else
{
// output was too big, so now incur the expense of allocating
// a buf for holding suffient characters.
std::vector<char> buf;
buf.reserve( len+1 ); // reserve(), not resize() which writes. +1 for trailing nul.
len = vsnprintf( &buf[0], len+1, format, tmp );
result->append( &buf[0], &buf[0] + len );
}
va_end( tmp ); // Release the temporary va_list, initialised from ap
// Now do the actual printing
len = vsnprintf( result->data() + size, len + 1, format, ap );
return len;
}
@ -443,18 +425,18 @@ int OUTPUTFORMATTER::vprint( const char* fmt, va_list ap )
// we make a copy of va_list ap for the second call, if happens
va_list tmp;
va_copy( tmp, ap );
int ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, ap );
int ret = vsnprintf( m_buffer.data(), m_buffer.size(), fmt, ap );
if( ret >= (int) m_buffer.size() )
{
m_buffer.resize( ret + 1000 );
ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, tmp );
ret = vsnprintf( m_buffer.data(), m_buffer.size(), fmt, tmp );
}
va_end( tmp ); // Release the temporary va_list, initialised from ap
if( ret > 0 )
write( &m_buffer[0], ret );
write( m_buffer.data(), ret );
return ret;
}

View File

@ -30,6 +30,7 @@
// Code under test
#include <string_utils.h>
#include <richio.h>
/**
* Declare the test suite
@ -141,4 +142,42 @@ BOOST_AUTO_TEST_CASE( Double2Str )
}
}
/**
* Test the #vprint method.
*/
BOOST_AUTO_TEST_CASE( VPrint )
{
std::string output;
// Test 1: Basic strings and numbers
StrPrintf( &output, "Hello %s! ", "World" );
StrPrintf( &output, "Number: %d, ", 42 );
StrPrintf( &output, "Float: %.2f, ", 3.14 );
StrPrintf( &output, "Char: %c. ", 'A' );
BOOST_CHECK_EQUAL( output, std::string( "Hello World! Number: 42, Float: 3.14, Char: A. " ) );
output.clear();
// Test 2: Large string
std::string longString( 500, 'A' );
StrPrintf( &output, "%s", longString.c_str() );
BOOST_CHECK_EQUAL( output, longString );
output.clear();
// Test 3: Edge case with zero characters
StrPrintf( &output, "" );
BOOST_ASSERT( output.empty() );
// Test 4: Mixing small and large strings
StrPrintf( &output, "Small, " );
StrPrintf( &output, "%s, ", longString.c_str() );
StrPrintf( &output, "End." );
BOOST_CHECK_EQUAL( output, std::string( "Small, " + longString + ", End." ) );
output.clear();
// Test 5: Formatting with various data types
StrPrintf( &output, "%d %s %c %.2f", 123, "Hello", 'X', 9.876 );
BOOST_CHECK_EQUAL( output, std::string( "123 Hello X 9.88" ) );
output.clear();
}
BOOST_AUTO_TEST_SUITE_END()