medfall

A super great game engine
Log | Files | Refs

array.h (8736B)


      1 #pragma once
      2 
      3 #include <stdlib.h>
      4 
      5 #include "intrinsics.h"
      6 #include "ggformat.h"
      7 #include "strlcpy.h"
      8 #include "log.h"
      9 
     10 template< typename T >
     11 class array {
     12 public:
     13 	array() {
     14 		n = 0;
     15 	}
     16 
     17 	array( T * memory, size_t count ) {
     18 		ASSERT( count == 0 || memory != NULL );
     19 		n = count;
     20 		elems = memory;
     21 	}
     22 
     23 	T & operator[]( size_t i ) {
     24 		ASSERT( i < n );
     25 		return elems[ i ];
     26 	}
     27 
     28 	const T & operator[]( size_t i ) const {
     29 		ASSERT( i < n );
     30 		return elems[ i ];
     31 	}
     32 
     33 	array< T > operator+( size_t i ) {
     34 		ASSERT( i <= n );
     35 		return array< T >( elems + i, n - i );
     36 	}
     37 
     38 	const array< T > operator+( size_t i ) const {
     39 		ASSERT( i <= n );
     40 		return array< T >( elems + i, n - i );
     41 	}
     42 
     43 	bool in_range( size_t i ) const {
     44 		return i < n;
     45 	}
     46 
     47 	T * ptr() {
     48 		return elems;
     49 	}
     50 
     51 	const T * ptr() const {
     52 		return elems;
     53 	}
     54 
     55 	size_t num_bytes() const {
     56 		return sizeof( T ) * n;
     57 	}
     58 
     59 	T * begin() {
     60 		return elems;
     61 	}
     62 
     63 	T * end() {
     64 		return elems + n;
     65 	}
     66 
     67 	const T * begin() const {
     68 		return elems;
     69 	}
     70 
     71 	const T * end() const {
     72 		return elems + n;
     73 	}
     74 
     75 	array< T > slice( size_t start, size_t one_past_end ) {
     76 		ASSERT( start <= one_past_end );
     77 		ASSERT( one_past_end <= n );
     78 		return array< T >( elems + start, one_past_end - start );
     79 	}
     80 
     81 	const array< T > slice( size_t start, size_t one_past_end ) const {
     82 		ASSERT( start <= one_past_end );
     83 		ASSERT( one_past_end <= n );
     84 		return array< T >( elems + start, one_past_end - start );
     85 	}
     86 
     87 	template< typename S >
     88 	array< S > cast() {
     89 		ASSERT( num_bytes() % sizeof( S ) == 0 );
     90 		return array< S >( ( S * ) ptr(), num_bytes() / sizeof( S ) );
     91 	}
     92 
     93 	template< typename S >
     94 	const array< S > cast() const {
     95 		ASSERT( num_bytes() % sizeof( S ) == 0 );
     96 		return array< S >( ( S * ) ptr(), num_bytes() / sizeof( S ) );
     97 	}
     98 
     99 	size_t n;
    100 
    101 protected:
    102 	T * elems;
    103 };
    104 
    105 template< typename T >
    106 class array2d {
    107 public:
    108 	array2d() {
    109 		w = h = 0;
    110 	}
    111 
    112 	array2d( T * memory, size_t width, size_t height ) {
    113 		ASSERT( width * height == 0 || memory != NULL );
    114 		w = width;
    115 		h = height;
    116 		elems = memory;
    117 	}
    118 
    119 	array2d( array< T > a, size_t width, size_t height ) {
    120 		ASSERT( width * height == a.n );
    121 		elems = a.ptr();
    122 		w = width;
    123 		h = height;
    124 	}
    125 
    126 	T & operator()( size_t x, size_t y ) {
    127 		ASSERT( in_range( x, y ) );
    128 		return elems[ y * w + x ];
    129 	}
    130 
    131 	const T & operator()( size_t x, size_t y ) const {
    132 		ASSERT( in_range( x, y ) );
    133 		return elems[ y * w + x ];
    134 	}
    135 
    136 	bool in_range( size_t x, size_t y ) const {
    137 		return x < w && y < h;
    138 	}
    139 
    140 	T try_get( size_t x, size_t y, T def ) const {
    141 		if( !in_range( x, y ) )
    142 			return def;
    143 		return elems[ y * w + x ];
    144 	}
    145 
    146 	T * ptr() {
    147 		return elems;
    148 	}
    149 
    150 	const T * ptr() const {
    151 		return elems;
    152 	}
    153 
    154 	array< T > row( size_t r ) {
    155 		return array< T >( elems + r * w, w );
    156 	}
    157 
    158 	const array< T > row( size_t r ) const {
    159 		return array< T >( elems + r * w, w );
    160 	}
    161 
    162 	size_t num_bytes() const {
    163 		return sizeof( T ) * w * h;
    164 	}
    165 
    166 	template< typename S >
    167 	array2d< S > cast() {
    168 		ASSERT( sizeof( S ) == sizeof( T ) );
    169 		return array2d< S >( ( S * ) ptr(), w, h );
    170 	}
    171 
    172 	template< typename S >
    173 	const array2d< S > cast() const {
    174 		ASSERT( sizeof( S ) == sizeof( T ) );
    175 		return array2d< S >( ( S * ) ptr(), w, h );
    176 	}
    177 
    178 	size_t w, h;
    179 
    180 private:
    181 	T * elems;
    182 };
    183 
    184 // TODO: sucky duplication
    185 template< typename T, size_t N >
    186 class StaticArray {
    187 public:
    188 	T & operator[]( size_t i ) {
    189 		ASSERT( i < N );
    190 		return elems[ i ];
    191 	}
    192 
    193 	const T & operator[]( size_t i ) const {
    194 		ASSERT( i < N );
    195 		return elems[ i ];
    196 	}
    197 
    198 	array< T > operator+( size_t i ) {
    199 		ASSERT( i <= N );
    200 		return array< T >( elems + i, N - i );
    201 	}
    202 
    203 	const array< T > operator+( size_t i ) const {
    204 		ASSERT( i <= N );
    205 		return array< T >( elems + i, N - i );
    206 	}
    207 
    208 	bool in_range( size_t i ) const {
    209 		return i < N;
    210 	}
    211 
    212 	T try_get( size_t i, T def ) const {
    213 		if( !in_range( i ) )
    214 			return def;
    215 		return elems[ i ];
    216 	}
    217 
    218 	T * ptr() {
    219 		return elems;
    220 	}
    221 
    222 	const T * ptr() const {
    223 		return elems;
    224 	}
    225 
    226 	size_t size() const {
    227 		return N;
    228 	}
    229 
    230 	size_t num_bytes() const {
    231 		return sizeof( T ) * N;
    232 	}
    233 
    234 	T * begin() {
    235 		return elems;
    236 	}
    237 
    238 	T * end() {
    239 		return elems + N;
    240 	}
    241 
    242 	const T * begin() const {
    243 		return elems;
    244 	}
    245 
    246 	const T * end() const {
    247 		return elems + N;
    248 	}
    249 
    250 	array< T > slice( size_t start, size_t one_past_end ) {
    251 		ASSERT( start <= one_past_end );
    252 		ASSERT( one_past_end <= N );
    253 		return array< T >( elems + start, one_past_end - start );
    254 	}
    255 
    256 	const array< T > slice( size_t start, size_t one_past_end ) const {
    257 		ASSERT( start <= one_past_end );
    258 		ASSERT( one_past_end <= N );
    259 		return array< T >( elems + start, one_past_end - start );
    260 	}
    261 
    262 	template< typename S >
    263 	array< S > cast() {
    264 		ASSERT( num_bytes() % sizeof( S ) == 0 );
    265 		return array< S >( ( S * ) ptr(), num_bytes() / sizeof( S ) );
    266 	}
    267 
    268 	template< typename S >
    269 	const array< S > cast() const {
    270 		ASSERT( num_bytes() % sizeof( S ) == 0 );
    271 		return array< S >( ( S * ) ptr(), num_bytes() / sizeof( S ) );
    272 	}
    273 
    274 	operator array< T >() {
    275 		return array< T >( elems, N );
    276 	}
    277 
    278 private:
    279 	T elems[ N ];
    280 };
    281 
    282 // TODO: pluggable allocators
    283 template< typename T >
    284 class DynamicArray {
    285 public:
    286 	NONCOPYABLE( DynamicArray );
    287 
    288 	DynamicArray( size_t initial_capacity = 0 ) {
    289 		n = 0;
    290 		capacity = initial_capacity;
    291 		elems = NULL;
    292 		if( initial_capacity > 0 ) {
    293 			elems = realloc_array( elems, capacity );
    294 		}
    295 	}
    296 
    297 	~DynamicArray() {
    298 		free( elems );
    299 	}
    300 
    301 	size_t add( const T & x ) {
    302 		size_t idx = extend( 1 );
    303 		elems[ idx ] = x;
    304 		return idx;
    305 	}
    306 
    307 	void clear() {
    308 		n = 0;
    309 	}
    310 
    311 	void resize( size_t new_size ) {
    312 		if( new_size < n ) {
    313 			n = new_size;
    314 			return;
    315 		}
    316 
    317 		if( new_size <= capacity ) {
    318 			n = new_size;
    319 			return;
    320 		}
    321 
    322 		size_t new_capacity = max( size_t( 64 ), capacity );
    323 		while( new_capacity < new_size ) {
    324 			new_capacity *= 2;
    325 		}
    326 
    327 		T * new_elems = realloc_array( elems, new_capacity );
    328 		if( new_elems == NULL ) {
    329 			FATAL( "couldn't allocate for DynamicArray" );
    330 		}
    331 		elems = new_elems;
    332 		capacity = new_capacity;
    333 		n = new_size;
    334 	}
    335 
    336 	size_t extend( size_t by ) {
    337 		size_t old_size = n;
    338 		resize( n + by );
    339 		return old_size;
    340 	}
    341 
    342 	T & operator[]( size_t i ) {
    343 		ASSERT( i < n );
    344 		return elems[ i ];
    345 	}
    346 
    347 	const T & operator[]( size_t i ) const {
    348 		ASSERT( i < n );
    349 		return elems[ i ];
    350 	}
    351 
    352 	array< T > operator+( size_t i ) {
    353 		ASSERT( i <= n );
    354 		return array< T >( elems + i, n - i );
    355 	}
    356 
    357 	const array< T > operator+( size_t i ) const {
    358 		ASSERT( i <= n );
    359 		return array< T >( elems + i, n - i );
    360 	}
    361 
    362 	bool in_range( size_t i ) const {
    363 		return i < n;
    364 	}
    365 
    366 	T try_get( size_t i, T def ) const {
    367 		if( !in_range( i ) )
    368 			return def;
    369 		return elems[ i ];
    370 	}
    371 
    372 	T * ptr() {
    373 		return elems;
    374 	}
    375 
    376 	const T * ptr() const {
    377 		return elems;
    378 	}
    379 
    380 	size_t size() const {
    381 		return n;
    382 	}
    383 
    384 	size_t num_bytes() const {
    385 		return sizeof( T ) * n;
    386 	}
    387 
    388 	T * begin() {
    389 		return elems;
    390 	}
    391 
    392 	T * end() {
    393 		return elems + n;
    394 	}
    395 
    396 	const T * begin() const {
    397 		return elems;
    398 	}
    399 
    400 	const T * end() const {
    401 		return elems + n;
    402 	}
    403 
    404 	array< T > slice( size_t start, size_t one_past_end ) {
    405 		ASSERT( start <= one_past_end );
    406 		ASSERT( one_past_end <= n );
    407 		return array< T >( elems + start, one_past_end - start );
    408 	}
    409 
    410 	const array< T > slice( size_t start, size_t one_past_end ) const {
    411 		ASSERT( start <= one_past_end );
    412 		ASSERT( one_past_end <= n );
    413 		return array< T >( elems + start, one_past_end - start );
    414 	}
    415 
    416 	operator const array< T >() const {
    417 		return array< T >( elems, n );
    418 	}
    419 
    420 private:
    421 	size_t n;
    422 	size_t capacity;
    423 	T * elems;
    424 };
    425 
    426 template< typename T, typename F >
    427 inline void visit( array< T > & a, F f ) {
    428 	f( a.n );
    429 	for( T & x : a ) f( x );
    430 }
    431 
    432 template< typename T, typename F >
    433 inline void visit( const array< T > & a, F f ) {
    434 	f( a.n );
    435 	for( const T & x : a ) f( x );
    436 }
    437 
    438 template< typename T >
    439 inline array< T > file_get_array( const char * path ) {
    440 	size_t len;
    441 	u8 * mem = file_get_contents( path, &len );
    442 
    443 	ASSERT( len % sizeof( T ) == 0 );
    444 	return array< T >( ( T * ) mem, len / sizeof( T ) );
    445 }
    446 
    447 template< typename T >
    448 static T bilerp( const array2d< T > arr, float x, float y ) {
    449 	size_t xi = ( size_t ) x;
    450 	size_t yi = ( size_t ) y;
    451 	size_t xi1 = min( xi + 1, arr.w - 1 );
    452 	size_t yi1 = min( yi + 1, arr.h - 1 );
    453 
    454 	float xf = x - xi;
    455 	float yf = y - yi;
    456 
    457 	T a = arr( xi, yi );
    458 	T b = arr( xi1, yi );
    459 	T c = arr( xi, yi1 );
    460 	T d = arr( xi1, yi1 );
    461 
    462 	T ab = lerp( a, xf, b );
    463 	T cd = lerp( c, xf, d );
    464 
    465 	return lerp( ab, yf, cd );
    466 }
    467 
    468 template< typename T >
    469 static T bilerp01( const array2d< T > arr, float x, float y ) {
    470 	return bilerp( arr, x * arr.w, y * arr.h );
    471 }
    472 
    473 inline void format( FormatBuffer * fb, array< const char > arr, const FormatOpts & opts ) {
    474 	if( fb->len < fb->capacity - 1 ) {
    475 		size_t len = min( arr.n, fb->capacity - fb->len - 1 );
    476 		memcpy( fb->buf + fb->len, arr.ptr(), len );
    477 		fb->buf[ fb->len + len ] = '\0';
    478 	}
    479 	fb->len += arr.n;
    480 }