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, /// `DataType.BYTE` 46 UBYTE = DataType.UBYTE, /// `DataType.UBYTE` 47 48 SHORT = DataType.SHORT, /// `DataType.SHORT` 49 USHORT = DataType.USHORT,/// `DataType.USHORT` 50 51 INT = DataType.INT, /// `DataType.INT` 52 UINT = DataType.UINT, /// `DataType.UINT` 53 54 LONG = DataType.LONG, /// `DataType.LONG` 55 ULONG = DataType.ULONG, /// `DataType.ULONG` 56 57 FLOAT = DataType.FLOAT, /// `DataType.FLOAT` 58 DOUBLE = DataType.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 /// count of components in element 309 size_t comp = 1; 310 311 /// type of one component 312 DataType type = DataType.RAWBYTE; 313 314 invariant() { assert( comp > 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( 1, assocDataType!T ); 331 else static if( isStaticArray!T ) 332 return ElemInfo( T.length, assocDataType!( typeof(T.init[0]) ) ); 333 else static if( isStaticVector!T ) 334 return ElemInfo( T.length, assocDataType!( T.datatype ) ); 335 else static if( isStaticMatrix!T ) 336 return ElemInfo( T.width * T.height, assocDataType!( T.datatype ) ); 337 else static assert(0,"unsupported type"); 338 } 339 340 /// 341 unittest 342 { 343 static assert( ElemInfo.fromType!vec2 == ElemInfo( 2, DataType.FLOAT ) ); 344 static assert( ElemInfo.fromType!mat4 == ElemInfo( 16, DataType.FLOAT ) ); 345 static assert( ElemInfo.fromType!(int[2]) == ElemInfo( 2, DataType.INT ) ); 346 static assert( ElemInfo.fromType!float == ElemInfo( 1, DataType.FLOAT ) ); 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( size_t comp, DataType type=DataType.RAWBYTE ) 357 { 358 this.comp = comp; 359 this.type = type; 360 } 361 362 /// 363 this( in ElemInfo ei ) 364 { 365 this.comp = ei.comp; 366 this.type = ei.type; 367 } 368 369 const @property 370 { 371 /++ bytes per element 372 returns: 373 typeSize * comp 374 +/ 375 size_t bpe() { return typeSize * comp; } 376 377 /// size of component 378 size_t typeSize() { return dataTypeSize(type); } 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 392 { 393 /// 394 size_t size; 395 /// 396 void* ptr; 397 398 this(T)( size_t size, T* data ) 399 { 400 this.size = size; 401 ptr = cast(void*)data; 402 } 403 404 this(T)( size_t size, in T* data ) const 405 { 406 this.size = size; 407 ptr = cast(void*)data; 408 } 409 } 410 411 /// 412 union AlienArray(T) 413 { 414 /// 415 ArrayData raw; 416 /// 417 T[] arr; 418 /// 419 alias type=T; 420 /// 421 alias arr this; 422 } 423 424 /// 425 auto getTypedArray(T,X)( size_t sz, X* addr ) pure nothrow 426 { 427 static if( is( Unqual!(X) == X ) ) 428 return AlienArray!T( ArrayData( sz, addr ) ); 429 else 430 return const AlienArray!T( const ArrayData( sz, addr ) ); 431 } 432 433 /// 434 unittest 435 { 436 float[] buf = [ 1.1f, 2.2, 3.3, 4.4, 5.5 ]; 437 auto a = getTypedArray!float( 2, cast(void*)(buf.ptr + 1) ); 438 import std.stdio; 439 assert( eq( a, [2.2, 3.3] ) ); 440 a[0] = 10; 441 assert( eq( buf, [1.1, 10, 3.3, 4.4, 5.5] ) ); 442 } 443 444 /// 445 unittest 446 { 447 448 ubyte[] buf = [ 1, 2, 3, 4 ]; 449 auto a = getTypedArray!void( 4, cast(void*)buf ); 450 assert( eq( cast(ubyte[])a, buf ) ); 451 } 452 453 /// 454 unittest 455 { 456 static struct TT { ubyte val; } 457 458 ubyte[] fnc( in TT[] data ) pure 459 { return getTypedArray!ubyte( data.length, data.ptr ).arr.dup; } 460 461 auto tt = [ TT(0), TT(1), TT(3) ]; 462 assert( eq( fnc( tt ), cast(ubyte[])[0,1,3] ) ); 463 } 464 465 /// 466 template convertValue( DataType DT ) 467 { 468 auto convertValue(T)( T val ) pure 469 { 470 alias SDT = storeDataType!DT; 471 472 static if( isDirectDataType!DT ) 473 return cast(SDT)( val ); 474 else static if( DT == DataType.RAWBYTE ) 475 static assert( 0, "can't convert any value to RAWBYTE" ); 476 else 477 { 478 static if( isFloatingPoint!T ) 479 { 480 static if( isSigned!SDT ) 481 { 482 enforce( val >= -1 && val <= 1, "value exceed signed limits [-1,1]" ); 483 return cast(SDT)( (val>0?SDT.max:SDT.min) * abs(val) ); 484 } 485 else 486 { 487 enforce( val >= 0 && val <= 1, "value exceed unsigned limits [0,1]" ); 488 return cast(SDT)( SDT.max * val ); 489 } 490 } 491 else static assert(0, "can't convert int value to fixed point value" ); 492 } 493 } 494 } 495 496 /// 497 unittest 498 { 499 static assert( convertValue!(DataType.NORM_FIXED)(1.0) == int.max ); 500 static assert( convertValue!(DataType.NORM_FIXED)(0.5) == int.max/2 ); 501 static assert( convertValue!(DataType.NORM_FIXED)(0.0) == 0 ); 502 static assert( convertValue!(DataType.NORM_FIXED)(-0.5) == int.min/2 ); 503 static assert( convertValue!(DataType.NORM_FIXED)(-1.0) == int.min ); 504 static assert( is( typeof( convertValue!(DataType.NORM_FIXED)(1.0) ) == int ) ); 505 } 506 507 unittest 508 { 509 static assert( convertValue!(DataType.BYTE)(1) == 1 ); 510 static assert( is( typeof( convertValue!(DataType.BYTE)(1) ) == byte ) ); 511 512 static assert( convertValue!(DataType.FLOAT)(1) == 1 ); 513 static assert( convertValue!(DataType.FLOAT)(1.1) == 1.1 ); 514 static assert( is( typeof( convertValue!(DataType.FLOAT)(1) ) == float ) ); 515 516 static assert( convertValue!(DataType.UNORM_QUART)(1.0) == ubyte.max ); 517 static assert( convertValue!(DataType.UNORM_QUART)(0.5) == ubyte.max/2 ); 518 static assert( convertValue!(DataType.UNORM_QUART)(0.0) == 0 ); 519 static assert( is( typeof( convertValue!(DataType.UNORM_QUART)(1.0) ) == ubyte ) ); 520 521 static assert( convertValue!(DataType.UNORM_HALF)(1.0) == ushort.max ); 522 static assert( convertValue!(DataType.UNORM_HALF)(0.5) == ushort.max/2 ); 523 static assert( convertValue!(DataType.UNORM_HALF)(0.0) == 0 ); 524 static assert( is( typeof( convertValue!(DataType.UNORM_HALF)(1.0) ) == ushort ) ); 525 526 static assert( convertValue!(DataType.UNORM_FIXED)(1.0) == uint.max ); 527 static assert( convertValue!(DataType.UNORM_FIXED)(0.5) == uint.max/2 ); 528 static assert( convertValue!(DataType.UNORM_FIXED)(0.0) == 0 ); 529 static assert( is( typeof( convertValue!(DataType.UNORM_FIXED)(1.0) ) == uint ) ); 530 531 static assert( convertValue!(DataType.UNORM_DOUBLE)(1.0) == ulong.max ); 532 static assert( convertValue!(DataType.UNORM_DOUBLE)(0.5) == ulong.max/2 ); 533 static assert( convertValue!(DataType.UNORM_DOUBLE)(0.0) == 0 ); 534 static assert( is( typeof( convertValue!(DataType.UNORM_DOUBLE)(1.0) ) == ulong ) ); 535 536 static assert( convertValue!(DataType.NORM_QUART)(1.0) == byte.max ); 537 static assert( convertValue!(DataType.NORM_QUART)(0.5) == byte.max/2 ); 538 static assert( convertValue!(DataType.NORM_QUART)(0.0) == 0 ); 539 static assert( convertValue!(DataType.NORM_QUART)(-0.5) == byte.min/2 ); 540 static assert( convertValue!(DataType.NORM_QUART)(-1.0) == byte.min ); 541 static assert( is( typeof( convertValue!(DataType.NORM_QUART)(1.0) ) == byte ) ); 542 543 static assert( convertValue!(DataType.NORM_HALF)(1.0) == short.max ); 544 static assert( convertValue!(DataType.NORM_HALF)(0.5) == short.max/2 ); 545 static assert( convertValue!(DataType.NORM_HALF)(0.0) == 0 ); 546 static assert( convertValue!(DataType.NORM_HALF)(-0.5) == short.min/2 ); 547 static assert( convertValue!(DataType.NORM_HALF)(-1.0) == short.min ); 548 static assert( is( typeof( convertValue!(DataType.NORM_HALF)(1.0) ) == short ) ); 549 550 static assert( convertValue!(DataType.NORM_FIXED)(1.0) == int.max ); 551 static assert( convertValue!(DataType.NORM_FIXED)(0.5) == int.max/2 ); 552 static assert( convertValue!(DataType.NORM_FIXED)(0.0) == 0 ); 553 static assert( convertValue!(DataType.NORM_FIXED)(-0.5) == int.min/2 ); 554 static assert( convertValue!(DataType.NORM_FIXED)(-1.0) == int.min ); 555 static assert( is( typeof( convertValue!(DataType.NORM_FIXED)(1.0) ) == int ) ); 556 557 static assert( convertValue!(DataType.NORM_DOUBLE)(1.0) == long.max ); 558 static assert( convertValue!(DataType.NORM_DOUBLE)(0.5) == long.max/2 ); 559 static assert( convertValue!(DataType.NORM_DOUBLE)(0.0) == 0 ); 560 static assert( convertValue!(DataType.NORM_DOUBLE)(-0.5) == long.min/2 ); 561 static assert( convertValue!(DataType.NORM_DOUBLE)(-1.0) == long.min ); 562 static assert( is( typeof( convertValue!(DataType.NORM_DOUBLE)(1.0) ) == long ) ); 563 564 assert( mustExcept({ convertValue!(DataType.NORM_FIXED)(1.1); }) ); 565 assert( !mustExcept({ convertValue!(DataType.NORM_FIXED)(-0.1); }) ); 566 567 assert( mustExcept({ convertValue!(DataType.UNORM_FIXED)(1.1); }) ); 568 assert( mustExcept({ convertValue!(DataType.UNORM_FIXED)(-0.1); }) ); 569 } 570 571 /// untyped data assign 572 void utDataAssign(T...)( in ElemInfo elem, void* buffer, in T vals ) pure 573 if( is(typeof(flatData!real(vals))) ) 574 in 575 { 576 assert( buffer !is null ); 577 assert( elem.comp == flatData!real(vals).length ); 578 } 579 body 580 { 581 enum fmt = q{ 582 auto dst = getTypedArray!(storeDataType!(%1$s))( elem.comp, buffer ); 583 auto src = flatData!real(vals); 584 foreach( i, ref t; dst ) 585 t = convertValue!(%1$s)( src[i] ); 586 }; 587 mixin( getSwitchDataType( "elem.type", fmt, ["RAWBYTE": "can't operate RAWBYTE"] ) ); 588 } 589 590 /// 591 unittest 592 { 593 float[] buf = [ 1.1, 2.2, 3.3, 4.4, 5.5, 6.6 ]; 594 595 utDataAssign( ElemInfo( 3, DataType.FLOAT ), cast(void*)buf.ptr, vec3(8,9,10) ); 596 597 assert( eq( buf, [8,9,10,4.4,5.5,6.6] ) ); 598 } 599 600 /++ 601 binary operation between untyped buffers 602 603 Params: 604 info = common to all buffers information 605 dst = result buffer ptr 606 uta = buffer ptr A 607 utb = buffer ptr B 608 +/ 609 void utDataOp(string op)( in ElemInfo elem, void* dst, void* utb ) pure 610 if( ( op == "+" || op == "-" || op == "*" || op == "/" ) ) 611 in 612 { 613 assert( dst !is null ); 614 assert( utb !is null ); 615 } 616 body 617 { 618 enum fmt = format( q{ 619 alias SDT = storeDataType!(%%1$s); 620 auto ta = getTypedArray!SDT( elem.comp, dst ); 621 auto tb = getTypedArray!SDT( elem.comp, utb ); 622 foreach( i, ref r; ta ) 623 r = cast(SDT)( ta[i] %s tb[i] ); 624 }, op ); 625 mixin( getSwitchDataType( "elem.type", fmt, ["RAWBYTE": "can't operate RAWBYTE"] ) ); 626 } 627 628 /// 629 unittest 630 { 631 ubyte[] a = [ 10, 20, 30, 40 ]; 632 ubyte[] b = [ 60, 70, 40, 20 ]; 633 634 utDataOp!"+"( ElemInfo( 4, DataType.UNORM_QUART ), a.ptr, b.ptr ); 635 636 assert( eq( a, [70,90,70,60] ) ); 637 638 utDataOp!"+"( ElemInfo( 2, DataType.UBYTE ), a.ptr, a.ptr + 2 ); 639 640 assert( eq( a, [140,150,70,60] ) ); 641 } 642 643 /++ generate switch for all DataType elements 644 645 Params: 646 subj = past as `switch( subj )` 647 fmt = body of all cases past as formated with one argument (DataType) string 648 except = exception in selected cases 649 650 Example: 651 enum fmt = q{ 652 auto dst = getTypedArray!(storeDataType!(%1$s))( info.comp, buffer ); 653 auto src = flatData!real(vals); 654 foreach( i, ref t; dst ) 655 t = convertValue!(%1$s)( src[i] ); 656 }; 657 writeln( genSwitchDataType( "info.type", fmt, ["RAWBYTE": "can't operate RAWBYTE"] ) ); 658 659 Output like this: 660 661 final switch( info.type ) { 662 case DataType.RAWBYTE: throw new DataTypeException( "can't operate RAWBYTE" ); 663 case DataType.BYTE: 664 auto dst = getTypedArray!(storeDataType!(DataType.BYTE))( info.comp, buffer ); 665 auto src = flatData!real(vals); 666 foreach( i, ref t; dst ) 667 t = convertValue!(DataType.BYTE)( src[i] ); 668 break; 669 case DataType.UBYTE: 670 auto dst = getTypedArray!(storeDataType!(DataType.UBYTE))( info.comp, buffer ); 671 auto src = flatData!real(vals); 672 foreach( i, ref t; dst ) 673 t = convertValue!(DataType.UBYTE)( src[i] ); 674 break; 675 ... 676 } 677 +/ 678 string getSwitchDataType( string subj, string fmt, string[string] except ) pure 679 { 680 string[] ret = [ format( `final switch( %s ) {`, subj ) ]; 681 682 auto _type( string dt ) { return "DataType." ~ dt; } 683 auto _case( string dt ) { return "case " ~ _type(dt) ~ ": "; } 684 685 auto fmt_case( string dt, string fmt ) 686 { return _case(dt) ~ "\n" ~ format( fmt, _type(dt) ) ~ "\nbreak;"; } 687 688 auto fmt_except( string dt, string msg ) 689 { return _case( dt ) ~ format( `throw new DataTypeException( "%s" );`, msg ); } 690 691 foreach( dt; [EnumMembers!DataType].map!(a=>to!string(a)) ) 692 { 693 if( dt in except ) ret ~= fmt_except( dt, except[dt] ); 694 else ret ~= fmt_case( dt, fmt ); 695 } 696 697 ret ~= "}"; 698 699 return ret.join("\n"); 700 }