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 }