1 module des.stdx.type; 2 3 import std..string : format, join; 4 import std.algorithm; 5 import std.conv : to; 6 import std.traits; 7 import std.math : abs; 8 import std.exception : enforce; 9 10 import des.ts; 11 import des.stdx.range; 12 import des.stdx..string; 13 14 /// 15 class DataTypeException : Exception 16 { 17 this( string msg, string file=__FILE__, size_t line=__LINE__ ) @safe pure nothrow 18 { super( msg, file, line ); } 19 } 20 21 /// data types description for untyped `void[]` arrays 22 enum DataType 23 { 24 RAWBYTE, /// untyped data `ubyte` 25 BYTE, /// `byte` 26 UBYTE, /// `ubyte` 27 NORM_QUART, /// fixed point quartered [-1,1] `byte` 28 UNORM_QUART, /// fixed point quartered [0,1] `ubyte` 29 30 SHORT, /// `short` 31 USHORT, /// `ushort` 32 NORM_HALF, /// fixed point half [-1,1] `short` 33 UNORM_HALF, /// fixed point half [0,1] `ushort` 34 35 INT, /// `int` 36 UINT, /// `uint` 37 NORM_FIXED, /// fixed point [-1,1] `int` 38 UNORM_FIXED, /// fixed point [0,1] `uint` 39 40 LONG, /// `long` 41 ULONG, /// `ulong` 42 NORM_DOUBLE, /// fixed point double [-1,1] `long` 43 UNORM_DOUBLE, /// fixed point double [0,1] `ulong` 44 45 FLOAT, /// `float` 46 DOUBLE /// `double` 47 } 48 49 /// data types that has direct correspondence with Dlang data types 50 enum StoreDataType : DataType 51 { 52 BYTE = DataType.BYTE, /// `DataType.BYTE` 53 UBYTE = DataType.UBYTE, /// `DataType.UBYTE` 54 55 SHORT = DataType.SHORT, /// `DataType.SHORT` 56 USHORT = DataType.USHORT,/// `DataType.USHORT` 57 58 INT = DataType.INT, /// `DataType.INT` 59 UINT = DataType.UINT, /// `DataType.UINT` 60 61 LONG = DataType.LONG, /// `DataType.LONG` 62 ULONG = DataType.ULONG, /// `DataType.ULONG` 63 64 FLOAT = DataType.FLOAT, /// `DataType.FLOAT` 65 DOUBLE = DataType.DOUBLE /// `DataType.DOUBLE` 66 } 67 68 /++ 69 returns associated with type T DataType 70 71 * `byte` = `DataType.BYTE` 72 * `ubyte` = `DataType.UBYTE` 73 * `short` = `DataType.SHORT` 74 * `ushort` = `DataType.USHORT` 75 * `int` = `DataType.INT` 76 * `uint` = `DataType.UINT` 77 * `long` = `DataType.LONG` 78 * `ulong` = `DataType.ULONG` 79 * `float` = `DataType.FLOAT` 80 * `double` = `DataType.DOUBLE` 81 * `else` = `DataType.RAWBYTE` 82 returns: 83 enum DataType 84 +/ 85 template assocDataType(T) 86 { 87 static if( is( T == byte ) ) enum assocDataType = DataType.BYTE; 88 else static if( is( T == ubyte ) ) enum assocDataType = DataType.UBYTE; 89 else static if( is( T == short ) ) enum assocDataType = DataType.SHORT; 90 else static if( is( T == ushort ) ) enum assocDataType = DataType.USHORT; 91 else static if( is( T == int ) ) enum assocDataType = DataType.INT; 92 else static if( is( T == uint ) ) enum assocDataType = DataType.UINT; 93 else static if( is( T == long ) ) enum assocDataType = DataType.LONG; 94 else static if( is( T == ulong ) ) enum assocDataType = DataType.ULONG; 95 else static if( is( T == float ) ) enum assocDataType = DataType.FLOAT; 96 else static if( is( T == double ) ) enum assocDataType = DataType.DOUBLE; 97 else enum assocDataType = DataType.RAWBYTE; 98 } 99 100 /// size of associated data type 101 size_t dataTypeSize( DataType dt ) pure nothrow @nogc @safe 102 { 103 final switch( dt ) 104 { 105 case DataType.RAWBYTE: 106 case DataType.BYTE: 107 case DataType.UBYTE: 108 case DataType.NORM_QUART: 109 case DataType.UNORM_QUART: 110 return byte.sizeof; 111 112 case DataType.SHORT: 113 case DataType.USHORT: 114 case DataType.NORM_HALF: 115 case DataType.UNORM_HALF: 116 return short.sizeof; 117 118 case DataType.INT: 119 case DataType.UINT: 120 case DataType.NORM_FIXED: 121 case DataType.UNORM_FIXED: 122 return int.sizeof; 123 124 case DataType.LONG: 125 case DataType.ULONG: 126 case DataType.NORM_DOUBLE: 127 case DataType.UNORM_DOUBLE: 128 return long.sizeof; 129 130 case DataType.FLOAT: 131 return float.sizeof; 132 133 case DataType.DOUBLE: 134 return double.sizeof; 135 } 136 } 137 138 /++ 139 alias for assocated store type 140 141 * `DataType.RAWBYTE` = `ubyte` 142 * `DataType.BYTE` = `byte` 143 * `DataType.UBYTE` = `ubyte` 144 * `DataType.NORM_QUART` = `byte` 145 * `DataType.UNORM_QUART` = `ubyte` 146 * `DataType.SHORT` = `short` 147 * `DataType.USHORT` = `ushort` 148 * `DataType.NORM_HALF` = `short` 149 * `DataType.UNORM_HALF` = `ushort` 150 * `DataType.INT` = `int` 151 * `DataType.UINT` = `uint` 152 * `DataType.NORM_FIXED` = `int` 153 * `DataType.UNORM_FIXED` = `uint` 154 * `DataType.LONG` = `long` 155 * `DataType.ULONG` = `ulong` 156 * `DataType.NORM_DOUBLE` = `long` 157 * `DataType.UNORM_DOUBLE` = `ulong` 158 * `DataType.FLOAT` = `float` 159 * `DataType.DOUBLE` = `double` 160 161 See_Also: `DataType` 162 +/ 163 template storeDataType( DataType DT ) 164 { 165 static if( DT == DataType.RAWBYTE ) alias storeDataType = ubyte; 166 else static if( DT == DataType.BYTE ) alias storeDataType = byte; 167 else static if( DT == DataType.UBYTE ) alias storeDataType = ubyte; 168 else static if( DT == DataType.NORM_QUART ) alias storeDataType = byte; 169 else static if( DT == DataType.UNORM_QUART ) alias storeDataType = ubyte; 170 else static if( DT == DataType.SHORT ) alias storeDataType = short; 171 else static if( DT == DataType.USHORT ) alias storeDataType = ushort; 172 else static if( DT == DataType.NORM_HALF ) alias storeDataType = short; 173 else static if( DT == DataType.UNORM_HALF ) alias storeDataType = ushort; 174 else static if( DT == DataType.INT ) alias storeDataType = int; 175 else static if( DT == DataType.UINT ) alias storeDataType = uint; 176 else static if( DT == DataType.NORM_FIXED ) alias storeDataType = int; 177 else static if( DT == DataType.UNORM_FIXED ) alias storeDataType = uint; 178 else static if( DT == DataType.LONG ) alias storeDataType = long; 179 else static if( DT == DataType.ULONG ) alias storeDataType = ulong; 180 else static if( DT == DataType.NORM_DOUBLE ) alias storeDataType = long; 181 else static if( DT == DataType.UNORM_DOUBLE ) alias storeDataType = ulong; 182 else static if( DT == DataType.FLOAT ) alias storeDataType = float; 183 else static if( DT == DataType.DOUBLE ) alias storeDataType = double; 184 } 185 186 /++ 187 alias for conformation type 188 189 diff with [storeDataType](des/util/data/type/storeDataType.html): 190 191 * `DataType.NORM_QUART` = `float` 192 * `DataType.UNORM_QUART` = `float` 193 * `DataType.NORM_HALF` = `float` 194 * `DataType.UNORM_HALF` = `float` 195 * `DataType.NORM_FIXED` = `float` 196 * `DataType.UNORM_FIXED` = `float` 197 * `DataType.NORM_DOUBLE` = `double` 198 * `DataType.UNORM_DOUBLE` = `double` 199 200 See_Also: 201 202 * `DataType` 203 * `storeDataType` 204 +/ 205 template conformDataType( DataType DT ) 206 { 207 static if( DT == DataType.RAWBYTE ) alias conformDataType = void; 208 else static if( DT == DataType.BYTE ) alias conformDataType = byte; 209 else static if( DT == DataType.UBYTE ) alias conformDataType = ubyte; 210 else static if( DT == DataType.NORM_QUART ) alias conformDataType = float; 211 else static if( DT == DataType.UNORM_QUART ) alias conformDataType = float; 212 else static if( DT == DataType.SHORT ) alias conformDataType = short; 213 else static if( DT == DataType.USHORT ) alias conformDataType = ushort; 214 else static if( DT == DataType.NORM_HALF ) alias conformDataType = float; 215 else static if( DT == DataType.UNORM_HALF ) alias conformDataType = float; 216 else static if( DT == DataType.INT ) alias conformDataType = int; 217 else static if( DT == DataType.UINT ) alias conformDataType = uint; 218 else static if( DT == DataType.NORM_FIXED ) alias conformDataType = float; 219 else static if( DT == DataType.UNORM_FIXED ) alias conformDataType = float; 220 else static if( DT == DataType.LONG ) alias conformDataType = long; 221 else static if( DT == DataType.ULONG ) alias conformDataType = ulong; 222 else static if( DT == DataType.NORM_DOUBLE ) alias conformDataType = double; 223 else static if( DT == DataType.UNORM_DOUBLE ) alias conformDataType = double; 224 else static if( DT == DataType.FLOAT ) alias conformDataType = float; 225 else static if( DT == DataType.DOUBLE ) alias conformDataType = double; 226 } 227 228 /// check `is( storeDataType!DT == conformDataType!DT )` for DataType DT 229 template isDirectDataType( DataType DT ) 230 { enum isDirectDataType = is( storeDataType!DT == conformDataType!DT ); } 231 232 unittest 233 { 234 import std..string; 235 236 template F( DataType DT ) 237 { 238 enum F = (storeDataType!DT).sizeof == dataTypeSize(DT); 239 static assert( F, format("%s",DT) ); 240 } 241 242 static assert( F!( DataType.RAWBYTE ) ); 243 static assert( F!( DataType.BYTE ) ); 244 static assert( F!( DataType.UBYTE ) ); 245 static assert( F!( DataType.NORM_QUART ) ); 246 static assert( F!( DataType.UNORM_QUART ) ); 247 static assert( F!( DataType.SHORT ) ); 248 static assert( F!( DataType.USHORT ) ); 249 static assert( F!( DataType.NORM_HALF ) ); 250 static assert( F!( DataType.UNORM_HALF ) ); 251 static assert( F!( DataType.INT ) ); 252 static assert( F!( DataType.UINT ) ); 253 static assert( F!( DataType.NORM_FIXED ) ); 254 static assert( F!( DataType.UNORM_FIXED ) ); 255 static assert( F!( DataType.LONG ) ); 256 static assert( F!( DataType.ULONG ) ); 257 static assert( F!( DataType.NORM_DOUBLE ) ); 258 static assert( F!( DataType.UNORM_DOUBLE ) ); 259 static assert( F!( DataType.FLOAT ) ); 260 static assert( F!( DataType.DOUBLE ) ); 261 262 static assert( F!( StoreDataType.BYTE ) ); 263 static assert( F!( StoreDataType.UBYTE ) ); 264 static assert( F!( StoreDataType.SHORT ) ); 265 static assert( F!( StoreDataType.USHORT ) ); 266 static assert( F!( StoreDataType.INT ) ); 267 static assert( F!( StoreDataType.UINT ) ); 268 static assert( F!( StoreDataType.LONG ) ); 269 static assert( F!( StoreDataType.ULONG ) ); 270 static assert( F!( StoreDataType.FLOAT ) ); 271 static assert( F!( StoreDataType.DOUBLE ) ); 272 } 273 274 unittest 275 { 276 static assert( !isDirectDataType!( DataType.RAWBYTE ) ); 277 static assert( isDirectDataType!( DataType.BYTE ) ); 278 static assert( isDirectDataType!( DataType.UBYTE ) ); 279 static assert( !isDirectDataType!( DataType.NORM_QUART ) ); 280 static assert( !isDirectDataType!( DataType.UNORM_QUART ) ); 281 static assert( isDirectDataType!( DataType.SHORT ) ); 282 static assert( isDirectDataType!( DataType.USHORT ) ); 283 static assert( !isDirectDataType!( DataType.NORM_HALF ) ); 284 static assert( !isDirectDataType!( DataType.UNORM_HALF ) ); 285 static assert( isDirectDataType!( DataType.INT ) ); 286 static assert( isDirectDataType!( DataType.UINT ) ); 287 static assert( !isDirectDataType!( DataType.NORM_FIXED ) ); 288 static assert( !isDirectDataType!( DataType.UNORM_FIXED ) ); 289 static assert( isDirectDataType!( DataType.LONG ) ); 290 static assert( isDirectDataType!( DataType.ULONG ) ); 291 static assert( !isDirectDataType!( DataType.NORM_DOUBLE ) ); 292 static assert( !isDirectDataType!( DataType.UNORM_DOUBLE ) ); 293 static assert( isDirectDataType!( DataType.FLOAT ) ); 294 static assert( isDirectDataType!( DataType.DOUBLE ) ); 295 296 static assert( isDirectDataType!( StoreDataType.BYTE ) ); 297 static assert( isDirectDataType!( StoreDataType.UBYTE ) ); 298 static assert( isDirectDataType!( StoreDataType.SHORT ) ); 299 static assert( isDirectDataType!( StoreDataType.USHORT ) ); 300 static assert( isDirectDataType!( StoreDataType.INT ) ); 301 static assert( isDirectDataType!( StoreDataType.UINT ) ); 302 static assert( isDirectDataType!( StoreDataType.LONG ) ); 303 static assert( isDirectDataType!( StoreDataType.ULONG ) ); 304 static assert( isDirectDataType!( StoreDataType.FLOAT ) ); 305 static assert( isDirectDataType!( StoreDataType.DOUBLE ) ); 306 } 307 308 /++ 309 Description for untyped arrays with multidimension elements 310 +/ 311 struct ElemInfo 312 { 313 /// count of components in element 314 size_t comp = 1; 315 316 /// type of one component 317 DataType type = DataType.RAWBYTE; 318 319 invariant() { assert( comp > 0 ); } 320 321 pure @safe nothrow @nogc 322 { 323 /++ get ElemInfo from type 324 + 325 + works with: 326 + * single numeric 327 + * static arrays of numeric 328 +/ 329 // TODO: user types with member `T[N] data` or `T[H][W] data` 330 static ElemInfo fromType(T)() @property 331 if( !hasIndirections!T ) 332 { 333 static if( isNumeric!T ) 334 return ElemInfo( 1, assocDataType!T ); 335 else static if( isStaticArray!T ) 336 return ElemInfo( T.length, assocDataType!( typeof(T.init[0]) ) ); 337 else static assert( 0, "unsupported type" ); 338 } 339 340 /// 341 unittest 342 { 343 static assert( ElemInfo.fromType!(int[2]) == ElemInfo( 2, DataType.INT ) ); 344 static assert( ElemInfo.fromType!float == ElemInfo( 1, DataType.FLOAT ) ); 345 346 static class A{} 347 348 static assert( !__traits(compiles, ElemInfo.fromType!A ) ); 349 static assert( !__traits(compiles, ElemInfo.fromType!(int[]) ) ); 350 static assert( !__traits(compiles, ElemInfo.fromType!dvec ) ); 351 } 352 353 /// 354 this( size_t comp, DataType type=DataType.RAWBYTE ) 355 { 356 this.comp = comp; 357 this.type = type; 358 } 359 360 /// 361 this( in ElemInfo ei ) 362 { 363 this.comp = ei.comp; 364 this.type = ei.type; 365 } 366 367 const @property 368 { 369 /++ bytes per element 370 returns: 371 typeSize * comp 372 +/ 373 size_t bpe() { return typeSize * comp; } 374 375 /// size of component 376 size_t typeSize() { return dataTypeSize(type); } 377 } 378 } 379 } 380 381 /// 382 struct ArrayData 383 { 384 /// 385 size_t size; 386 /// 387 void* ptr; 388 389 /// 390 this(T)( size_t size, T* data ) 391 { 392 this.size = size; 393 ptr = cast(void*)data; 394 } 395 396 /// 397 this(T)( size_t size, in T* data ) const 398 { 399 this.size = size; 400 ptr = cast(void*)data; 401 } 402 } 403 404 /+ no doc because bad doc comment parsing for union 405 members of union sets as public variables of module 406 (hmod commit 406ba02) 407 +/ 408 union Array(T) 409 { 410 ArrayData raw; 411 T[] arr; 412 alias type=T; 413 alias arr this; 414 } 415 416 /// 417 auto getTypedArray(T,X)( size_t sz, X* addr ) pure nothrow 418 { 419 static if( is( Unqual!(X) == X ) ) 420 return Array!T( ArrayData( sz, addr ) ); 421 else 422 return const Array!T( const ArrayData( sz, addr ) ); 423 } 424 425 /// 426 unittest 427 { 428 float[] buf = [ 1.1f, 2.2, 3.3, 4.4, 5.5 ]; 429 auto a = getTypedArray!float( 2, cast(void*)(buf.ptr + 1) ); 430 assertEq( a, [2.2, 3.3] ); 431 a[0] = 10; 432 a[1] = 12; 433 assertEq( buf, [1.1, 10, 12, 4.4, 5.5] ); 434 } 435 436 /// 437 unittest 438 { 439 440 ubyte[] buf = [ 1, 2, 3, 4 ]; 441 auto a = getTypedArray!void( 4, cast(void*)buf ); 442 assertEq( cast(ubyte[])a, buf ); 443 } 444 445 /// 446 unittest 447 { 448 static struct TT { ubyte val; } 449 450 ubyte[] fnc( in TT[] data ) pure 451 { return getTypedArray!ubyte( data.length, data.ptr ).arr.dup; } 452 453 auto tt = [ TT(0), TT(1), TT(3) ]; 454 assertEq( fnc( tt ), cast(ubyte[])[0,1,3] ); 455 } 456 457 /// 458 template convertValue( DataType DT ) 459 { 460 alias SDT = storeDataType!DT; 461 462 auto convertValue(T,string file=__FILE__,size_t line=__LINE__ )( T val ) pure 463 { 464 static if( isDirectDataType!DT ) 465 return cast(SDT)( val ); 466 else static if( DT == DataType.RAWBYTE ) 467 static assert( 0, "can't convert any value to RAWBYTE" ); 468 else static if( isFloatingPoint!T ) 469 { 470 static if( isSigned!SDT ) 471 { 472 enforce( -1 <= val && val <= 1, 473 new DataTypeException( "value " ~ floatToStr(val) ~ 474 " exceed signed limits [-1,1]", file, line ) ); 475 return cast(SDT)( (val>0?SDT.max:SDT.min) * abs(val) ); 476 } 477 else 478 { 479 enforce( 0 <= val && val <= 1, 480 new DataTypeException( "value " ~ floatToStr(val) ~ 481 " exceed unsigned limits [0,1]", file, line ) ); 482 return cast(SDT)( SDT.max * val ); 483 } 484 } 485 else static assert( 0, "can't convert int value to fixed point value" ); 486 } 487 } 488 489 /// 490 unittest 491 { 492 { 493 auto r = convertValue!(DataType.BYTE)(1); 494 static assert( is( typeof(r) == byte ) ); 495 static assert( convertValue!(DataType.BYTE)(2) == 2 ); 496 } 497 498 { 499 auto r = convertValue!(DataType.FLOAT)(1); 500 static assert( is( typeof(r) == float ) ); 501 static assert( convertValue!(DataType.FLOAT)(1) == 1 ); 502 static assert( convertValue!(DataType.FLOAT)(1.1) == 1.1 ); 503 } 504 505 { 506 auto r = convertValue!(DataType.UNORM_QUART)(1.0); 507 static assert( is( typeof(r) == ubyte ) ); 508 static assert( convertValue!(DataType.UNORM_QUART)(1.0) == ubyte.max ); 509 static assert( convertValue!(DataType.UNORM_QUART)(0.5) == ubyte.max/2 ); 510 static assert( convertValue!(DataType.UNORM_QUART)(0.0) == 0 ); 511 } 512 513 { 514 auto r = convertValue!(DataType.UNORM_HALF)(1.0); 515 static assert( is( typeof(r) == ushort ) ); 516 static assert( convertValue!(DataType.UNORM_HALF)(1.0) == ushort.max ); 517 static assert( convertValue!(DataType.UNORM_HALF)(0.5) == ushort.max/2 ); 518 static assert( convertValue!(DataType.UNORM_HALF)(0.0) == 0 ); 519 } 520 521 { 522 auto r = convertValue!(DataType.UNORM_FIXED)(1.0); 523 static assert( is( typeof(r) == uint ) ); 524 static assert( convertValue!(DataType.UNORM_FIXED)(1.0) == uint.max ); 525 static assert( convertValue!(DataType.UNORM_FIXED)(0.5) == uint.max/2 ); 526 static assert( convertValue!(DataType.UNORM_FIXED)(0.0) == 0 ); 527 } 528 529 { 530 auto r = convertValue!(DataType.UNORM_DOUBLE)(1.0); 531 static assert( is( typeof(r) == ulong ) ); 532 static assert( convertValue!(DataType.UNORM_DOUBLE)(1.0) == ulong.max ); 533 static assert( convertValue!(DataType.UNORM_DOUBLE)(0.5) == ulong.max/2 ); 534 static assert( convertValue!(DataType.UNORM_DOUBLE)(0.0) == 0 ); 535 } 536 537 { 538 auto r = convertValue!(DataType.NORM_QUART)(1.0); 539 static assert( is( typeof(r) == byte ) ); 540 static assert( convertValue!(DataType.NORM_QUART)(1.0) == byte.max ); 541 static assert( convertValue!(DataType.NORM_QUART)(0.5) == byte.max/2 ); 542 static assert( convertValue!(DataType.NORM_QUART)(0.0) == 0 ); 543 static assert( convertValue!(DataType.NORM_QUART)(-0.5) == byte.min/2 ); 544 static assert( convertValue!(DataType.NORM_QUART)(-1.0) == byte.min ); 545 } 546 547 { 548 auto r = convertValue!(DataType.NORM_HALF)(1.0); 549 static assert( is( typeof(r) == short ) ); 550 static assert( convertValue!(DataType.NORM_HALF)(1.0) == short.max ); 551 static assert( convertValue!(DataType.NORM_HALF)(0.5) == short.max/2 ); 552 static assert( convertValue!(DataType.NORM_HALF)(0.0) == 0 ); 553 static assert( convertValue!(DataType.NORM_HALF)(-0.5) == short.min/2 ); 554 static assert( convertValue!(DataType.NORM_HALF)(-1.0) == short.min ); 555 } 556 557 { 558 auto r = convertValue!(DataType.NORM_FIXED)(1.0); 559 static assert( is( typeof(r) == int ) ); 560 static assert( convertValue!(DataType.NORM_FIXED)(1.0) == int.max ); 561 static assert( convertValue!(DataType.NORM_FIXED)(0.5) == int.max/2 ); 562 static assert( convertValue!(DataType.NORM_FIXED)(0.0) == 0 ); 563 static assert( convertValue!(DataType.NORM_FIXED)(-0.5) == int.min/2 ); 564 static assert( convertValue!(DataType.NORM_FIXED)(-1.0) == int.min ); 565 } 566 567 { 568 auto r = convertValue!(DataType.NORM_DOUBLE)(1.0); 569 static assert( is( typeof(r) == long ) ); 570 static assert( convertValue!(DataType.NORM_DOUBLE)(1.0) == long.max ); 571 static assert( convertValue!(DataType.NORM_DOUBLE)(0.5) == long.max/2 ); 572 static assert( convertValue!(DataType.NORM_DOUBLE)(0.0) == 0 ); 573 static assert( convertValue!(DataType.NORM_DOUBLE)(-0.5) == long.min/2 ); 574 static assert( convertValue!(DataType.NORM_DOUBLE)(-1.0) == long.min ); 575 } 576 577 convertValue!(DataType.NORM_FIXED)(-0.1); 578 assertThrown!DataTypeException( convertValue!(DataType.NORM_FIXED)(1.1) ); 579 580 assertThrown!DataTypeException( convertValue!(DataType.UNORM_FIXED)(-0.1) ); 581 assertThrown!DataTypeException( convertValue!(DataType.UNORM_FIXED)(1.1) ); 582 } 583 584 /// untyped data assign 585 void utDataAssign(T...)( in ElemInfo elem, void* buffer, in T vals ) pure 586 if( is(typeof(flatData!real(vals))) ) 587 in 588 { 589 assert( buffer !is null ); 590 assert( elem.comp == getFlatLength(vals) ); 591 } 592 body 593 { 594 enum fmt = q{ 595 auto dst = arrayOutputRange( getTypedArray!(storeDataType!(%1$s))( elem.comp, buffer ).arr ); 596 auto conv_%2$s( ElementTypeRec!(T[0]) a ) pure { return convertValue!(%1$s)(a); } 597 mapFlat!conv_%2$s( dst, vals ); 598 }; 599 mixin( getSwitchDataType( "elem.type", fmt, ["RAWBYTE": "can't operate RAWBYTE"] ) ); 600 } 601 602 /// 603 unittest 604 { 605 float[] buf = [ 1.1, 2.2, 3.3, 4.4, 5.5, 6.6 ]; 606 607 struct vec3 { double[3] dd; alias dd this; } 608 609 utDataAssign( ElemInfo( 3, DataType.FLOAT ), cast(void*)(buf.ptr+1), vec3([8,9,10]) ); 610 611 assert( eq( buf, [1.1,8,9,10,5.5,6.6] ) ); 612 } 613 614 /++ binary operation between untyped buffers 615 + 616 + logicaly equals opAssign ( a op= b ) 617 + 618 + Params: 619 + elem = common to all buffers information 620 + dst = result buffer ptr 621 + utb = buffer ptr B 622 +/ 623 void utDataOp(string op)( in ElemInfo elem, void* dst, void* utb ) pure 624 if( ( op == "+" || op == "-" || op == "*" || op == "/" ) ) 625 in 626 { 627 assert( dst !is null ); 628 assert( utb !is null ); 629 } 630 body 631 { 632 enum fmt = format( q{ 633 alias SDT = storeDataType!(%%1$s); // %%2$s not used 634 auto ta = getTypedArray!SDT( elem.comp, dst ); 635 auto tb = getTypedArray!SDT( elem.comp, utb ); 636 foreach( i, ref r; ta ) 637 r = cast(SDT)( ta[i] %s tb[i] ); 638 }, op ); 639 mixin( getSwitchDataType( "elem.type", fmt, ["RAWBYTE": "can't operate RAWBYTE"] ) ); 640 } 641 642 /// 643 unittest 644 { 645 ubyte[] a = [ 10, 20, 30, 40 ]; 646 ubyte[] b = [ 60, 70, 40, 20 ]; 647 648 utDataOp!"+"( ElemInfo( 4, DataType.UNORM_QUART ), a.ptr, b.ptr ); 649 650 assertEq( a, [70,90,70,60] ); 651 652 utDataOp!"+"( ElemInfo( 2, DataType.UBYTE ), a.ptr, a.ptr + 2 ); 653 654 assert( eq( a, [140,150,70,60] ) ); 655 } 656 657 private string getSwitchDataType( string subj, string fmt, string[string] except ) pure 658 { 659 string[] ret = [ format( `final switch( %s ) {`, subj ) ]; 660 661 auto _type( string dt ) { return "DataType." ~ dt; } 662 auto _case( string dt ) { return "case " ~ _type(dt) ~ ": "; } 663 664 auto fmt_case( string dt, string fmt ) 665 { return _case(dt) ~ "\n" ~ format( fmt, _type(dt), dt ) ~ "\nbreak;"; } 666 667 auto fmt_except( string dt, string msg ) 668 { return _case( dt ) ~ format( `throw new DataTypeException( "%s" );`, msg ); } 669 670 foreach( dt; [EnumMembers!DataType].map!(a=>to!string(a)) ) 671 { 672 if( dt in except ) ret ~= fmt_except( dt, except[dt] ); 673 else ret ~= fmt_case( dt, fmt ); 674 } 675 676 ret ~= "}"; 677 678 return ret.join("\n"); 679 }