medfall

A super great game engine
Log | Files | Refs

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