Skip to content

Commit

Permalink
setup so tests can be run by a user of the library. add set/get alloc…
Browse files Browse the repository at this point in the history
…ator to support yojimbo usage
  • Loading branch information
gafferongames committed Dec 25, 2023
1 parent 53d6a1f commit 02cbec0
Show file tree
Hide file tree
Showing 2 changed files with 326 additions and 291 deletions.
328 changes: 324 additions & 4 deletions serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ namespace serialize
** Read a 64-bit variable-length integer from memory starting at p[0].
** Return the number of bytes read. The value is stored in *v.
*/
uint8_t serialize_get_varint( const unsigned char * p, uint64_t * v )
inline uint8_t serialize_get_varint( const unsigned char * p, uint64_t * v )
{
uint32_t a, b, s;

Expand Down Expand Up @@ -972,7 +972,7 @@ namespace serialize
return 9;
}

uint8_t serialize_get_varint32( const unsigned char * p, uint32_t * v )
inline uint8_t serialize_get_varint32( const unsigned char * p, uint32_t * v )
{
uint32_t a, b;

Expand Down Expand Up @@ -1094,7 +1094,7 @@ namespace serialize
** Return the number of bytes that will be needed to store the given
** 64-bit integer.
*/
int serialize_measure_varint( uint64_t v )
inline int serialize_measure_varint( uint64_t v )
{
int i;
for ( i = 1; (v>>=7) != 0; i++ ) { serialize_assert(i<10); }
Expand All @@ -1113,7 +1113,7 @@ namespace serialize
Base stream constructor.
*/

explicit BaseStream() : m_context( NULL ) {}
explicit BaseStream() : m_context( NULL ), m_allocator( NULL ) {}

/**
Set a context on the stream.
Expand All @@ -1137,9 +1137,31 @@ namespace serialize
return m_context;
}

/**
Set an allocator pointer on the stream.
This can be helpful if you want to perform allocations within serialize functions.
*/

void SetAllocator( void * allocator )
{
m_allocator = allocator;
}

/**
Get the allocator pointer set on the stream.
@returns The allocator pointer. May be NULL.
*/

void * GetAllocator() const
{
return m_allocator;
}

private:

void * m_context; ///< The context pointer set on the stream. May be NULL.
void * m_allocator; ///< The allocator pointer set on the stream. May be NULL.
};

/**
Expand Down Expand Up @@ -2307,4 +2329,302 @@ namespace serialize
#define write_int_relative serialize_int_relative
}

#if SERIALIZE_ENABLE_TESTS

#include <time.h>

static void CheckHandler( const char * condition,
const char * function,
const char * file,
int line )
{
printf( "check failed: ( %s ), function %s, file %s, line %d\n", condition, function, file, line );
#ifndef NDEBUG
#if defined( __GNUC__ )
__builtin_trap();
#elif defined( _MSC_VER )
__debugbreak();
#endif
#endif
exit( 1 );
}

#define check( condition ) \
do \
{ \
if ( !(condition) ) \
{ \
CheckHandler( #condition, __FUNCTION__, __FILE__, __LINE__ ); \
} \
} while(0)

void test_endian()
{
uint32_t value = 0x11223344;

const char * bytes = (const char*) &value;

#if SERIALIZE_LITTLE_ENDIAN

check( bytes[0] == 0x44 );
check( bytes[1] == 0x33 );
check( bytes[2] == 0x22 );
check( bytes[3] == 0x11 );

#else // #if SERIALIZE_LITTLE_ENDIAN

check( bytes[3] == 0x44 );
check( bytes[2] == 0x33 );
check( bytes[1] == 0x22 );
check( bytes[0] == 0x11 );

#endif // #if SERIALIZE_LITTLE_ENDIAN
}

void test_bitpacker()
{
const int BufferSize = 256;

uint8_t buffer[BufferSize];

serialize::BitWriter writer( buffer, BufferSize );

check( writer.GetData() == buffer );
check( writer.GetBitsWritten() == 0 );
check( writer.GetBytesWritten() == 0 );
check( writer.GetBitsAvailable() == BufferSize * 8 );

writer.WriteBits( 0, 1 );
writer.WriteBits( 1, 1 );
writer.WriteBits( 10, 8 );
writer.WriteBits( 255, 8 );
writer.WriteBits( 1000, 10 );
writer.WriteBits( 50000, 16 );
writer.WriteBits( 9999999, 32 );
writer.FlushBits();

const int bitsWritten = 1 + 1 + 8 + 8 + 10 + 16 + 32;

check( writer.GetBytesWritten() == 10 );
check( writer.GetBitsWritten() == bitsWritten );
check( writer.GetBitsAvailable() == BufferSize * 8 - bitsWritten );

const int bytesWritten = writer.GetBytesWritten();

check( bytesWritten == 10 );

memset( buffer + bytesWritten, 0, BufferSize - bytesWritten );

serialize::BitReader reader( buffer, bytesWritten );

check( reader.GetBitsRead() == 0 );
check( reader.GetBitsRemaining() == bytesWritten * 8 );

uint32_t a = reader.ReadBits( 1 );
uint32_t b = reader.ReadBits( 1 );
uint32_t c = reader.ReadBits( 8 );
uint32_t d = reader.ReadBits( 8 );
uint32_t e = reader.ReadBits( 10 );
uint32_t f = reader.ReadBits( 16 );
uint32_t g = reader.ReadBits( 32 );

check( a == 0 );
check( b == 1 );
check( c == 10 );
check( d == 255 );
check( e == 1000 );
check( f == 50000 );
check( g == 9999999 );

check( reader.GetBitsRead() == bitsWritten );
check( reader.GetBitsRemaining() == bytesWritten * 8 - bitsWritten );
}

void test_bits_required()
{
check( serialize::bits_required( 0, 0 ) == 0 );
check( serialize::bits_required( 0, 1 ) == 1 );
check( serialize::bits_required( 0, 2 ) == 2 );
check( serialize::bits_required( 0, 3 ) == 2 );
check( serialize::bits_required( 0, 4 ) == 3 );
check( serialize::bits_required( 0, 5 ) == 3 );
check( serialize::bits_required( 0, 6 ) == 3 );
check( serialize::bits_required( 0, 7 ) == 3 );
check( serialize::bits_required( 0, 8 ) == 4 );
check( serialize::bits_required( 0, 255 ) == 8 );
check( serialize::bits_required( 0, 65535 ) == 16 );
check( serialize::bits_required( 0, 4294967295 ) == 32 );
}

const int MaxItems = 11;

struct TestData
{
TestData()
{
memset( this, 0, sizeof( TestData ) );
}

int a,b,c;
uint32_t d : 8;
uint32_t e : 8;
uint32_t f : 8;
bool g;
uint32_t v32;
uint64_t v64;
int numItems;
int items[MaxItems];
float float_value;
float compressed_float_value;
double double_value;
uint64_t uint64_value;
uint32_t varint32_value;
uint64_t varint64_value;
int int_relative;
uint8_t bytes[17];
char string[256];
};

struct TestContext
{
int min;
int max;
};

struct TestObject
{
TestData data;

void Init()
{
data.a = 1;
data.b = -2;
data.c = 150;
data.d = 55;
data.e = 255;
data.f = 127;
data.g = true;

data.numItems = MaxItems / 2;
for ( int i = 0; i < data.numItems; ++i )
data.items[i] = i + 10;

data.compressed_float_value = 2.13f;
data.float_value = 3.1415926f;
data.double_value = 1 / 3.0;
data.uint64_value = 0x1234567898765432L;
data.varint32_value = 123456;
data.varint64_value = 123456789101112;
data.int_relative = 5;

for ( int i = 0; i < (int) sizeof( data.bytes ); ++i )
data.bytes[i] = rand() % 255;

strcpy( data.string, "hello world!" );
}

template <typename Stream> bool Serialize( Stream & stream )
{
const TestContext & context = *(const TestContext*) stream.GetContext();

serialize_int( stream, data.a, context.min, context.max );
serialize_int( stream, data.b, context.min, context.max );

serialize_int( stream, data.c, -100, 10000 );

serialize_bits( stream, data.d, 6 );
serialize_bits( stream, data.e, 8 );
serialize_bits( stream, data.f, 7 );

serialize_align( stream );

serialize_bool( stream, data.g );

serialize_int( stream, data.numItems, 0, MaxItems - 1 );
for ( int i = 0; i < data.numItems; ++i )
serialize_bits( stream, data.items[i], 8 );

serialize_float( stream, data.float_value );

serialize_compressed_float( stream, data.compressed_float_value, 0, 10, 0.01 );

serialize_double( stream, data.double_value );

serialize_uint64( stream, data.uint64_value );

serialize_varint32( stream, data.varint32_value );

serialize_varint64( stream, data.varint64_value );

serialize_int_relative( stream, data.a, data.int_relative );

serialize_bytes( stream, data.bytes, sizeof( data.bytes ) );

serialize_string( stream, data.string, sizeof( data.string ) );

return true;
}

bool operator == ( const TestObject & other ) const
{
return memcmp( &data, &other.data, sizeof( TestData ) ) == 0;
}

bool operator != ( const TestObject & other ) const
{
return ! ( *this == other );
}
};

void test_stream()
{
const int BufferSize = 1024;

uint8_t buffer[BufferSize];

TestContext context;
context.min = -10;
context.max = +10;

serialize::WriteStream writeStream( buffer, BufferSize );

TestObject writeObject;
writeObject.Init();
writeStream.SetContext( &context );
writeObject.Serialize( writeStream );
writeStream.Flush();

const int bytesWritten = writeStream.GetBytesProcessed();

memset( buffer + bytesWritten, 0, BufferSize - bytesWritten );

TestObject readObject;
serialize::ReadStream readStream( buffer, bytesWritten );
readStream.SetContext( &context );
readObject.Serialize( readStream );

check( readObject == writeObject );
}

#define RUN_TEST( test_function ) \
do \
{ \
printf( #test_function "\n" ); \
test_function(); \
} \
while (0)

void serialize_test()
{
// while ( 1 )
{
RUN_TEST( test_endian );
RUN_TEST( test_bitpacker );
RUN_TEST( test_bits_required );
RUN_TEST( test_stream );
}
}

#endif // #if SERIALIZE_ENABLE_TESTS

#endif // #ifndef SERIALIZE_H
Loading

0 comments on commit 02cbec0

Please sign in to comment.