stream.h (3612B)
1 #pragma once 2 3 #include <string.h> 4 5 #include "intrinsics.h" 6 #include "platform_alignment.h" 7 8 struct ReadStream; 9 10 struct ReadStreamCheckpoint { 11 const ReadStream * rs; 12 const char * cursor; 13 bool ok; 14 bool used; 15 }; 16 17 struct ReadStream { 18 ReadStream( const void * buf, size_t n ) { 19 cursor = ( const char * ) buf; 20 one_past_end = cursor + n; 21 ok = true; 22 } 23 24 template< size_t N > 25 ReadStream( const char ( &buf )[ N ] ) : ReadStream( buf, N ) { } 26 27 bool done() const { 28 return ok && cursor == one_past_end; 29 } 30 31 ReadStreamCheckpoint checkpoint() const { 32 ReadStreamCheckpoint cp; 33 cp.rs = this; 34 cp.cursor = cursor; 35 cp.ok = ok; 36 cp.used = false; 37 return cp; 38 } 39 40 void reset( ReadStreamCheckpoint * cp ) { 41 ASSERT( cp->rs == this ); 42 ASSERT( !cp->used ); 43 44 cursor = cp->cursor; 45 ok = cp->ok; 46 cp->used = true; 47 } 48 49 template< typename T > 50 T * nocopy( size_t num_bytes ) { 51 ASSERT( num_bytes % sizeof( T ) == 0 ); 52 ASSERT( is_aligned( ( T * ) cursor ) ); 53 54 T * ret = ( T * ) cursor; 55 cursor += num_bytes; 56 return ret; 57 } 58 59 const char * cursor; 60 const char * one_past_end; 61 bool ok; 62 }; 63 64 struct WriteStream { 65 WriteStream( void * buf, size_t n ) { 66 start = ( char * ) buf; 67 cursor = start; 68 one_past_end = start + n; 69 ok = true; 70 } 71 72 template< size_t N > 73 WriteStream( char ( &buf )[ N ] ) : WriteStream( buf, N ) { } 74 75 size_t len() const { 76 return checked_cast< size_t >( cursor - start ); 77 } 78 79 char * start; 80 char * cursor; 81 char * one_past_end; 82 bool ok; 83 }; 84 85 static bool cpu_is_little_endian() { 86 u16 i = 1; 87 char * c = ( char * ) &i; 88 return c[ 0 ] == 1; 89 } 90 91 struct StreamSerialiser { 92 StreamSerialiser( WriteStream * s ) { 93 stream = s; 94 } 95 96 template< typename T > 97 void operator()( const T & x ) { 98 ASSERT( cpu_is_little_endian() ); 99 if( !stream->ok || checked_cast< size_t >( stream->one_past_end - stream->cursor ) < sizeof( T ) ) { 100 stream->ok = false; 101 return; 102 } 103 memcpy( stream->cursor, &x, sizeof( T ) ); 104 stream->cursor += sizeof( T ); 105 } 106 107 WriteStream * stream; 108 }; 109 110 struct StreamDeserialiser { 111 StreamDeserialiser( ReadStream * s ) { 112 stream = s; 113 } 114 115 template< typename T > 116 void operator()( T & x ) { 117 ASSERT( cpu_is_little_endian() ); 118 if( !stream->ok || checked_cast< size_t >( stream->one_past_end - stream->cursor ) < sizeof( T ) ) { 119 stream->ok = false; 120 x = T(); 121 return; 122 } 123 memcpy( &x, stream->cursor, sizeof( T ) ); 124 stream->cursor += sizeof( T ); 125 } 126 127 ReadStream * stream; 128 }; 129 130 template< typename T > 131 inline void read( ReadStream * stream, T * x ) { 132 visit( *x, StreamDeserialiser( stream ) ); 133 } 134 135 template< typename T > 136 inline void write( WriteStream * stream, const T & x ) { 137 visit( x, StreamSerialiser( stream ) ); 138 } 139 140 // TODO: endianness 141 inline void * reserve( WriteStream * stream, size_t size ) { 142 static u8 dummy_memory[ 64 ]; 143 ASSERT( size < sizeof( dummy_memory ) ); 144 145 if( !stream->ok || checked_cast< size_t >( stream->one_past_end - stream->cursor ) < size ) { 146 stream->ok = false; 147 return dummy_memory; 148 } 149 150 stream->cursor += size; 151 return stream->cursor - size; 152 } 153 154 #define DEF_READ_WRITE( T ) \ 155 inline T read_##T( ReadStream * stream ) { \ 156 T x; \ 157 read( stream, &x ); \ 158 return x; \ 159 } \ 160 inline void write_##T( WriteStream * stream, const T & x ) { \ 161 write( stream, x ); \ 162 } \ 163 inline void * reserve_##T( WriteStream * stream ) { \ 164 return reserve( stream, sizeof( T ) ); \ 165 } 166 167 DEF_READ_WRITE( u8 ) 168 DEF_READ_WRITE( u16 ) 169 DEF_READ_WRITE( u32 ) 170 DEF_READ_WRITE( u64 ) 171 DEF_READ_WRITE( s8 ) 172 DEF_READ_WRITE( s16 ) 173 DEF_READ_WRITE( s32 ) 174 DEF_READ_WRITE( s64 ) 175 DEF_READ_WRITE( float ) 176 DEF_READ_WRITE( double ) 177 178 #undef DEF_READ_WRITE