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