diff --git a/serialize.h b/serialize.h index c5b7cef..e7d5d09 100644 --- a/serialize.h +++ b/serialize.h @@ -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; @@ -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; @@ -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); } @@ -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. @@ -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. }; /** @@ -2307,4 +2329,302 @@ namespace serialize #define write_int_relative serialize_int_relative } +#if SERIALIZE_ENABLE_TESTS + +#include + +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 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 diff --git a/test.cpp b/test.cpp index 6d9452a..74e62da 100644 --- a/test.cpp +++ b/test.cpp @@ -23,290 +23,8 @@ */ #include "serialize.h" -#include -using namespace serialize; - -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]; - - 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 ); - - 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( bits_required( 0, 0 ) == 0 ); - check( bits_required( 0, 1 ) == 1 ); - check( bits_required( 0, 2 ) == 2 ); - check( bits_required( 0, 3 ) == 2 ); - check( bits_required( 0, 4 ) == 3 ); - check( bits_required( 0, 5 ) == 3 ); - check( bits_required( 0, 6 ) == 3 ); - check( bits_required( 0, 7 ) == 3 ); - check( bits_required( 0, 8 ) == 4 ); - check( bits_required( 0, 255 ) == 8 ); - check( bits_required( 0, 65535 ) == 16 ); - check( 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 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; - - 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; - 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) +extern void serialize_test(); int main() { @@ -314,10 +32,7 @@ int main() printf( "\n" ); - RUN_TEST( test_endian ); - RUN_TEST( test_bitpacker ); - RUN_TEST( test_bits_required ); - RUN_TEST( test_stream ); + serialize_test(); printf( "\n*** ALL TESTS PASS ***\n\n" );