1 /++ 2 Provides work with linear algebra vector and some aliases and functions. 3 +/ 4 module des.math.linear.vector; 5 6 import std.exception; 7 import std.traits; 8 import std.meta; 9 import std..string; 10 import std.math; 11 import std.algorithm; 12 13 import des.ts; 14 15 import des.math.util; 16 17 import des.math.linear.matrix; 18 19 /// checks type is vector 20 template isVector(E) 21 { 22 enum isVector = is( typeof(impl(E.init)) ); 23 void impl(size_t N,T)( in Vector!(N,T) ) {} 24 } 25 26 /// checks type is static vector 27 template isStaticVector(E) 28 { 29 static if( !isVector!E ) 30 enum isStaticVector = false; 31 else enum isStaticVector = E.isStatic; 32 } 33 34 /// checks type is dynamic vector 35 template isDynamicVector(E) 36 { 37 static if( !isVector!E ) 38 enum isDynamicVector = false; 39 else enum isDynamicVector = E.isDynamic; 40 } 41 42 unittest 43 { 44 static assert( !isStaticVector!float ); 45 static assert( !isDynamicVector!float ); 46 } 47 48 /++ 49 validate operation between types `T` and `E` 50 code: 51 mixin( `enum isValidOp = is( typeof( T.init ` ~ op ~ ` E.init ) : K );` ); 52 +/ 53 template isValidOp(string op,T,E,K=T) 54 { mixin( `enum isValidOp = is( typeof( T.init ` ~ op ~ ` E.init ) : K );` ); } 55 56 private string zerosVectorData( size_t N ) @property 57 { 58 string[] ret; 59 foreach( j; 0 .. N ) ret ~= "0"; 60 return "[" ~ ret.join(",") ~ "]"; 61 } 62 63 /// сhecks type E is vector and E.dims == N and E.datatype can casted to T 64 template isSpecVector(size_t N,T,E) 65 { 66 static if( !isVector!E ) enum isSpecVector = false; 67 else enum isSpecVector = E.dims == N && is( E.datatype : T ); 68 } 69 70 /++ 71 Params: 72 N = Number of dimensions, if 0 then vector is dynamic 73 T = data type 74 +/ 75 struct Vector(size_t N,T) 76 { 77 /// `N == 0` 78 enum bool isDynamic = N == 0; 79 /// `N != 0` 80 enum bool isStatic = N != 0; 81 /// equals `N` 82 enum size_t dims = N; 83 84 /// 85 static if( isStatic ) 86 { 87 static if( !isNumeric!T ) 88 /// if `isStatic` ( fills by zeros if `isNumeric!T` ) 89 T[N] data; 90 else T[N] data = mixin( zerosVectorData(N) ); 91 } 92 else T[] data; /// if `isDynamic` 93 94 /// 95 alias data this; 96 97 /// 98 alias datatype = T; 99 100 /// 101 alias selftype = Vector!(N,T); 102 103 /// `isSpecVector!(N,T)` 104 template isCompatible(E) { enum isCompatible = isSpecVector!(N,T,E); } 105 106 pure: 107 108 static if( isStatic ) enum length = N; 109 else 110 { 111 @property 112 { 113 size_t length() const { return data.length; } 114 void length( size_t nl ) { data.length = nl; } 115 } 116 } 117 118 /++ 119 + Vector can be constructed with different ways: 120 121 + * from single values 122 + * from arrays 123 + * from other vectors 124 +/ 125 this(E...)( in E vals ) 126 { 127 // not work with dynamic vectors 128 static assert( is(typeof(flatData!T(vals))), "args not compatible" ); 129 130 static if( isStatic ) 131 { 132 static if( hasNoDynamic!E && E.length > 1 ) 133 { 134 static assert( getElemCount!E == N * getElemCount!T, "wrong args count" ); 135 static assert( isConvertable!(T,E), "wrong args type" ); 136 mixin( vectorStaticFill!("T","data","vals",T,E) ); 137 } 138 else 139 { 140 auto buf = flatData!T(vals); 141 142 if( buf.length == length ) data[] = buf[]; 143 else if( buf.length == 1 ) data[] = buf[0]; 144 else enforce( false, "bad args length" ); 145 } 146 } 147 else data = flatData!T(vals); 148 } 149 150 static if( isDynamic ) 151 { 152 this(this) { data = data.dup; } 153 154 /// 155 static selftype fill(E...)( size_t K, in E vals ) 156 { 157 selftype ret; 158 ret.length = K; 159 if( E.length ) 160 { 161 auto d = flatData!T(vals); 162 foreach( i, ref val; ret.data ) val = d[i%$]; 163 } 164 else static if( isNumeric!T ) ret.data[] = 0; 165 return ret; 166 } 167 } 168 169 /// 170 auto opAssign(size_t K,E)( auto ref const(Vector!(K,E)) b ) 171 if( (K==N||K==0||N==0) && is( typeof(T(E.init)) ) ) 172 { 173 static if( isDynamic ) length = b.length; 174 foreach( i; 0 .. length ) data[i] = T(b[i]); 175 return this; 176 } 177 178 static if( N == 2 || N == 3 || N == 4 ) 179 { 180 static if( N == 2 ) enum AccessString = "x y|w h|u v"; 181 else 182 static if( N == 3 ) enum AccessString = "x y z|w h d|u v t|r g b"; 183 else 184 static if( N == 4 ) enum AccessString = "x y z w|r g b a"; 185 186 mixin accessByString!( N, T, "data", AccessString ); 187 } 188 189 /// 190 auto opUnary(string op)() const 191 if( op == "-" && is( typeof( T.init * (-1) ) : T ) ) 192 { 193 selftype ret; 194 static if( isDynamic ) ret.length = length; 195 foreach( i; 0 .. length ) 196 ret[i] = this[i] * -1; 197 return ret; 198 } 199 200 /++ 201 + Any binary operations execs per element 202 +/ 203 auto opBinary(string op,size_t K,E)( auto ref const(Vector!(K,E)) b ) const 204 if( isValidOp!(op,T,E) && (K==N||K==0||N==0) ) 205 { 206 selftype ret; 207 static if( isDynamic || b.isDynamic ) 208 enforce( length == b.length, "wrong length" ); 209 static if( isDynamic ) ret.length = length; 210 foreach( i; 0 .. length ) 211 mixin( `ret[i] = this[i] ` ~ op ~ ` b[i];` ); 212 return ret; 213 } 214 215 /// ditto 216 auto opBinary(string op,E)( auto ref const(E) b ) const 217 if( isValidOp!(op,T,E) && op != "+" && op != "-" ) 218 { 219 selftype ret; 220 static if( isDynamic ) ret.length = length; 221 foreach( i; 0 .. length ) 222 mixin( `ret[i] = this[i] ` ~ op ~ ` b;` ); 223 return ret; 224 } 225 226 /// ditto 227 auto opOpAssign(string op, E)( auto ref const(E) b ) 228 if( mixin( `is( typeof( this ` ~ op ~ ` b ) )` ) ) 229 { mixin( `return this = this ` ~ op ~ ` b;` ); } 230 231 /// only mul allowed 232 auto opBinaryRight(string op, E)( auto ref const(E) b ) const 233 if( isValidOp!(op,E,T,T) && op == "*" ) 234 { mixin( "return this " ~ op ~ " b;" ); } 235 236 /// checks all elements is finite 237 bool opCast(E)() const if( is( E == bool ) ) 238 { 239 foreach( v; data ) if( !isFinite(v) ) return false; 240 return true; 241 } 242 243 /// 244 const(E) opCast(E)() const if( is( T[] == E ) ) { return data.dup; } 245 /// 246 E opCast(E)() if( is( T[] == E ) ) { return data.dup; } 247 248 static if( is( typeof( T.init * T.init ) == T ) && 249 is( typeof( T.init + T.init ) == T ) ) 250 { 251 private alias __ftype = CommonType!(T,float); 252 253 const @property 254 { 255 /++ Square of euclidean length of the vector 256 257 only: 258 if( is( typeof( dot(selftype.init,selftype.init) ) ) ) 259 +/ 260 auto len2() { return dot(this,this); } 261 262 static if( is( typeof( sqrt( __ftype(this.len2) ) ) ) ) 263 { 264 /++ Euclidean length of the vector 265 266 only: 267 if( is( typeof( sqrt(CommonType!(T,float)(this.len2)) ) ) ) 268 +/ 269 auto len(E=__ftype)() { return sqrt( E(len2) ); } 270 271 static if( isValidOp!("/",T,__ftype) ) 272 { 273 /++ normalized vector 274 275 only: 276 if( isValidOp!("/",T,__ftype) ) 277 +/ 278 auto e() { return this / len; } 279 } 280 } 281 } 282 } 283 284 auto rebase(Args...)( auto ref const(Args) e ) const 285 if( allSatisfy!(isCompatible,Args) && Args.length == N ) 286 { 287 auto m = Matrix!(N,N,T)(e).T.inv; 288 return m * this; 289 } 290 } 291 292 /// 293 alias Vector2(T) = Vector!(2,T); 294 /// 295 alias Vector3(T) = Vector!(3,T); 296 /// 297 alias Vector4(T) = Vector!(4,T); 298 299 /// 300 alias fvec(size_t N) = Vector!(N,float); 301 /// 302 alias vec2 = fvec!2; 303 /// 304 alias vec3 = fvec!3; 305 /// 306 alias vec4 = fvec!4; 307 308 /// 309 alias dvec(size_t N) = Vector!(N,double); 310 /// 311 alias dvec2 = dvec!2; 312 /// 313 alias dvec3 = dvec!3; 314 /// 315 alias dvec4 = dvec!4; 316 317 /// 318 alias rvec(size_t N) = Vector!(N,real); 319 /// 320 alias rvec2 = rvec!2; 321 /// 322 alias rvec3 = rvec!3; 323 /// 324 alias rvec4 = rvec!4; 325 326 /// 327 alias bvec(size_t N) = Vector!(N,byte); 328 /// 329 alias bvec2 = bvec!2; 330 /// 331 alias bvec3 = bvec!3; 332 /// 333 alias bvec4 = bvec!4; 334 335 /// 336 alias ubvec(size_t N) = Vector!(N,ubyte); 337 /// 338 alias ubvec2 = ubvec!2; 339 /// 340 alias ubvec3 = ubvec!3; 341 /// 342 alias ubvec4 = ubvec!4; 343 344 /// 345 alias ivec(size_t N) = Vector!(N,int); 346 /// 347 alias ivec2 = ivec!2; 348 /// 349 alias ivec3 = ivec!3; 350 /// 351 alias ivec4 = ivec!4; 352 353 /// 354 alias uivec(size_t N) = Vector!(N,uint); 355 /// 356 alias uivec2 = uivec!2; 357 /// 358 alias uivec3 = uivec!3; 359 /// 360 alias uivec4 = uivec!4; 361 362 /// 363 alias lvec(size_t N) = Vector!(N,long); 364 /// 365 alias lvec2 = lvec!2; 366 /// 367 alias lvec3 = lvec!3; 368 /// 369 alias lvec4 = lvec!4; 370 371 /// 372 alias ulvec(size_t N) = Vector!(N,ulong); 373 /// 374 alias ulvec2 = ulvec!2; 375 /// 376 alias ulvec3 = ulvec!3; 377 /// 378 alias ulvec4 = ulvec!4; 379 380 unittest 381 { 382 static assert( is( Vector2!float == vec2 ) ); 383 static assert( is( Vector3!real == rvec3 ) ); 384 static assert( is( Vector4!double == dvec4 ) ); 385 } 386 387 /// 388 alias Vector!(0,byte) bvecD; 389 /// 390 alias Vector!(0,ubyte) ubvecD; 391 /// 392 alias Vector!(0,int) ivecD; 393 /// 394 alias Vector!(0,uint) uivecD; 395 /// 396 alias Vector!(0,short) svecD; 397 /// 398 alias Vector!(0,ushort)usvecD; 399 /// 400 alias Vector!(0,long) lvecD; 401 /// 402 alias Vector!(0,ulong) ulvecD; 403 /// 404 alias Vector!(0,float) vecD; 405 /// 406 alias Vector!(0,double) dvecD; 407 /// 408 alias Vector!(0,real) rvecD; 409 410 unittest 411 { 412 static assert( isVector!vec2 ); 413 static assert( isVector!vec3 ); 414 static assert( isVector!vec4 ); 415 static assert( isVector!dvec2 ); 416 static assert( isVector!dvec3 ); 417 static assert( isVector!dvec4 ); 418 static assert( isVector!ivec2 ); 419 static assert( isVector!ivec3 ); 420 static assert( isVector!ivec4 ); 421 static assert( isVector!vecD ); 422 static assert( isVector!ivecD ); 423 static assert( isVector!dvecD ); 424 425 static assert( isSpecVector!(2,float,vec2) ); 426 static assert( isSpecVector!(3,float,vec3) ); 427 static assert( isSpecVector!(4,float,vec4) ); 428 static assert( isSpecVector!(2,double,dvec2) ); 429 static assert( isSpecVector!(3,double,dvec3) ); 430 static assert( isSpecVector!(4,double,dvec4) ); 431 static assert( isSpecVector!(2,int,ivec2) ); 432 static assert( isSpecVector!(3,int,ivec3) ); 433 static assert( isSpecVector!(4,int,ivec4) ); 434 } 435 436 /// 437 unittest 438 { 439 static assert( Vector!(3,float).isStatic == true ); 440 static assert( Vector!(3,float).isDynamic == false ); 441 442 static assert( Vector!(0,float).isStatic == false ); 443 static assert( Vector!(0,float).isDynamic == true ); 444 445 static assert( isVector!(Vector!(3,float)) ); 446 static assert( isVector!(Vector!(0,float)) ); 447 448 static assert( Vector!(3,float).sizeof == float.sizeof * 3 ); 449 static assert( Vector!(0,float).sizeof == (float[]).sizeof ); 450 451 static assert( Vector!(3,float).length == 3 ); 452 } 453 454 /// 455 unittest 456 { 457 assert( eq( Vector!(3,float)(1,2,3), [1,2,3] ) ); 458 459 auto a = Vector!(3,float)(1,2,3); 460 assert( eq( Vector!(5,int)(0,a,4), [0,1,2,3,4] ) ); 461 462 static assert( !__traits(compiles, { auto v = Vector!(2,int)(1,2,3); } ) ); 463 464 { auto v = Vector!(0,int)(1,2,3); } // no exception 465 { auto v = Vector!(3,int)(1); } // no exception 466 467 auto b = Vector!(0,float)(1,2,3); 468 assert( eq( b.length, 3 ) ); 469 470 auto c = Vector!(3,float)(1); 471 assert( eq( c, [1,1,1] ) ); 472 auto d = c; 473 assert( eq( c, d ) ); 474 } 475 476 /// 477 unittest 478 { 479 static struct Test1 { float x,y,z; } 480 static assert( !__traits(compiles,Vector!(3,float)(Test1.init)) ); 481 482 static struct Test2 { float[3] data; alias data this; } 483 static assert( __traits(compiles,Vector!(3,float)(Test2.init)) ); 484 } 485 486 unittest 487 { 488 auto a = vec3(1,2,3); 489 490 auto a1 = const vec3(a); 491 auto a2 = const vec3(1,2,3); 492 auto a3 = const vec3(1); 493 494 auto a4 = shared vec3(a); 495 auto a5 = shared vec3(1,2,3); 496 auto a6 = shared vec3(1); 497 498 auto a7 = immutable vec3(a); 499 auto a8 = immutable vec3(1,2,3); 500 auto a9 = immutable vec3(1); 501 502 auto a10 = shared const vec3(a); 503 auto a11 = shared const vec3(1,2,3); 504 auto a12 = shared const vec3(1); 505 506 a = vec3(a4.data); 507 } 508 509 /// convert vectors 510 unittest 511 { 512 auto a = ivec2(1,2); 513 auto b = vec2(a); 514 assert( eq( a, b ) ); 515 auto c = ivec2(b); 516 assert( eq( a, c ) ); 517 } 518 519 unittest 520 { 521 auto a = vec3(2); 522 assert( eq( -a, [-2,-2,-2] ) ); 523 } 524 525 /// 526 unittest 527 { 528 auto a = Vector!(3,int)(1,2,3); 529 assert( eq( a.x, a.r ) ); 530 assert( eq( a.y, a.g ) ); 531 assert( eq( a.z, a.b ) ); 532 assert( eq( a.x, a.u ) ); 533 assert( eq( a.y, a.v ) ); 534 assert( eq( a.z, a.t ) ); 535 } 536 537 /// 538 unittest 539 { 540 auto a = vec3(1,2,3); 541 542 assert( eq( a.opDispatch!"x", 1 ) ); 543 assert( eq( a.y, 2 ) ); 544 assert( eq( a.z, 3 ) ); 545 546 a.opDispatch!"x" = 2; 547 a.x = 2; 548 assert( eq( a.x, 2 ) ); 549 } 550 551 /// 552 unittest 553 { 554 auto a = vec3(1,2,3); 555 556 auto b = a.opDispatch!"xy"; 557 auto c = a.xx; 558 auto d = a.xxxyyzyx; 559 560 static assert( is(typeof(b) == Vector!(2,float) ) ); 561 static assert( is(typeof(c) == Vector!(2,float) ) ); 562 static assert( is(typeof(d) == Vector!(8,float) ) ); 563 564 assert( eq( b, [1,2] ) ); 565 assert( eq( c, [1,1] ) ); 566 assert( eq( d, [1,1,1,2,2,3,2,1] ) ); 567 } 568 569 /// 570 unittest 571 { 572 auto a = vec3(1,2,3); 573 auto b = dvec4(4,5,6,7); 574 auto c = vecD( 9, 10 ); 575 a.opDispatch!"xz"( b.yw ); 576 assert( eq( a, [5,2,7] ) ); 577 a.zy = c; 578 assert( eq( a, [5,10,9] ) ); 579 static assert( !__traits(compiles, a.xy=vec3(1,2,3)) ); 580 static assert( !__traits(compiles, a.xx=vec2(1,2)) ); 581 auto d = a.zxy = b.wyx; 582 static assert( is( d.datatype == double ) ); 583 assert( eq( d, [ 7,5,4 ] ) ); 584 assert( eq( a, [ 5,4,7 ] ) ); 585 a.yzx = a.zxz; 586 assert( eq( a, [ 7,7,5 ] ) ); 587 } 588 589 /// 590 unittest 591 { 592 auto a = vec3(1,2,3); 593 auto b = vecD(1,2,3); 594 auto c = a + b; 595 assert( is( typeof(c) == vec3 ) ); 596 auto d = b + a; 597 assert( is( typeof(d) == vecD ) ); 598 assert( eq( c, d ) ); 599 auto f = ivec3(1,2,3); 600 auto c1 = a + f; 601 assert( is( typeof(c1) == vec3 ) ); 602 auto d1 = ivec3(f) + ivec3(a); 603 assert( is( typeof(d1) == ivec3 ) ); 604 assert( eq( c1, d ) ); 605 assert( eq( c, d1 ) ); 606 607 a *= 2; 608 b *= 2; 609 auto e = b *= 2; 610 assert( eq( a, [2,4,6] ) ); 611 assert( eq( b, a*2 ) ); 612 613 auto x = 2 * a; 614 assert( eq( x, [4,8,12] ) ); 615 616 assert( !!x ); 617 x[0] = float.nan; 618 assert( !x ); 619 } 620 621 /// 622 unittest 623 { 624 auto a = vec3(2,4,6); 625 a /= 2; 626 assert( eq( a, [1,2,3] ) ); 627 } 628 629 /// 630 unittest 631 { 632 auto a = vecD(1,2,3); 633 634 auto b = vec3(a); 635 auto c = vecD(b); 636 637 assert( eq( a, b ) ); 638 assert( eq( a, c ) ); 639 } 640 /// 641 unittest 642 { 643 auto a = vec3(2,2,1); 644 assert( eq( a.rebase(vec3(2,0,0),vec3(0,2,0),vec3(0,0,2)), [1,1,.5] ) ); 645 } 646 647 /// 648 unittest 649 { 650 auto a = vec3(1,2,3); 651 auto b = ivec3(1,2,3); 652 auto k = a.len2; 653 assert( is( typeof(k) == float ) ); 654 655 auto l = b.len2; 656 assert( is( typeof(l) == int ) ); 657 658 auto m = b.len; 659 assert( is( typeof(m) == float ) ); 660 661 auto n = b.len!real; 662 assert( is( typeof(n) == real ) ); 663 664 assert( is( typeof( vec3( 1, 2, 3 ).e ) == vec3 ) ); 665 assert( eq( a.e.len, 1 ) ); 666 } 667 668 /// 669 unittest 670 { 671 alias Vector!(3,cfloat) cvec3; 672 673 auto a = cvec3( 1-1i, 2+0i, 0+3i ); 674 static assert( __traits(compiles, a.e) ); 675 676 { auto k = a.e; } // no exception 677 } 678 679 /// 680 unittest 681 { 682 alias Vector!(3,Vector!(3,float)) mat3; 683 auto a = mat3( vec3(1,0,0), vec3(0,1,0), vec3(0,0,1) ); 684 685 a *= 2; 686 a += a; 687 688 assert( eq( a[0][0], 4 ) ); 689 assert( eq( a[1][1], 4 ) ); 690 assert( eq( a[2][2], 4 ) ); 691 692 assert( eq( a[0][1], 0 ) ); 693 assert( eq( a[1][2], 0 ) ); 694 assert( eq( a[2][1], 0 ) ); 695 696 a ^^= 2; 697 698 assert( eq( a[0][0], 16 ) ); 699 assert( eq( a[1][1], 16 ) ); 700 assert( eq( a[2][2], 16 ) ); 701 702 auto b = -a; 703 704 assert( eq( b[0][0], -16) ); 705 assert( eq( b[1][1], -16) ); 706 assert( eq( b[2][2], -16) ); 707 } 708 709 unittest 710 { 711 auto a = vecD(1,2,3); 712 auto b = a; 713 assert( eq( a, b ) ); 714 b[0] = 111; 715 assert( !eq( a, b ) ); 716 717 vecD c; 718 c = b; 719 assert( eq( c, b ) ); 720 b[0] = 222; 721 assert( !eq( c, b ) ); 722 } 723 724 unittest 725 { 726 auto a = vec3(1,2,3); 727 auto b = a; 728 assert( eq( a, b ) ); 729 b[0] = 111; 730 assert( !eq( a, b ) ); 731 } 732 733 /// dot multiplication for compaitable vectors. 734 auto dot(size_t N,size_t K,T,E)( auto ref const(Vector!(N,T)) a, 735 auto ref const(Vector!(K,E)) b ) 736 if( (N==K||K==0||N==0) && hasCompMltAndSum!(T,E) ) 737 { 738 static if( a.isDynamic || b.isDynamic ) 739 { 740 enforce( a.length == b.length, "wrong length" ); 741 enforce( a.length > 0, "zero length" ); 742 } 743 auto ret = cast(T)(a[0] * b[0]); 744 foreach( i; 1 .. a.length ) ret += cast(T)(a[i] * b[i]); 745 return ret; 746 } 747 748 /// 749 unittest 750 { 751 auto a = vec3(1,2,3); 752 auto b = vecD(1,2,3); 753 754 assert( eq( dot(a,b), 1+4+9 ) ); 755 } 756 757 bool hasCompMltAndSum(T,E)() pure 758 { return is( typeof( cast(T)(T.init * E.init) ) ) && is( typeof( T.init + T.init ) == T ); } 759 760 /// cross multiplication for compaitable vectors. 761 auto cross(size_t N,size_t K,T,E)( auto ref const(Vector!(N,T)) a, auto ref const(Vector!(K,E)) b ) 762 if( ((K==3||K==0)&&(N==3||N==0)) && hasCompMltAndSum!(T,E) ) 763 { 764 static if( a.isDynamic ) enforce( a.length == 3, "wrong length a" ); 765 static if( b.isDynamic ) enforce( b.length == 3, "wrong length b" ); 766 767 a.selftype ret; 768 static if( a.isDynamic ) ret.length = 3; 769 ret[0] = T(a[1] * b[2]) - T(a[2] * b[1]); 770 ret[1] = T(a[2] * b[0]) - T(a[0] * b[2]); 771 ret[2] = T(a[0] * b[1]) - T(a[1] * b[0]); 772 return ret; 773 } 774 775 /// 776 unittest 777 { 778 auto x = vec3(1,0,0); 779 auto y = vecD(0,1,0); 780 auto z = vecD(0,0,1); 781 782 assert( eq( cross(x,y), z ) ); 783 assert( eq( cross(y,z), x ) ); 784 assert( eq( cross(y,x), -z ) ); 785 assert( eq( cross(x,z), -y ) ); 786 assert( eq( cross(z,x), y ) ); 787 788 auto fy = vecD(0,1,0,0); 789 assertThrown( x * fy ); 790 auto cfy = vec4(0,1,0,0); 791 static assert( !__traits(compiles,x*cfy) ); 792 } 793 794 /// 795 mixin template accessByString( size_t N, T, string data, string AS, string VVASES=" ", string VVASVS="|") 796 if( isCompatibleArrayAccessStrings(N,AS,VVASES,VVASVS) ) 797 { 798 pure @property 799 { 800 import std..string; 801 import des.math.util; 802 803 T opDispatch(string v)() const 804 if( getIndex(AS,v,VVASES,VVASVS) != -1 ) 805 { mixin( format( "return this.%s[%d];", data, getIndex(AS,v,VVASES,VVASVS) ) ); } 806 807 ref T opDispatch(string v)() 808 if( getIndex(AS,v,VVASES,VVASVS) != -1 ) 809 { mixin( format( "return this.%s[%d];", data, getIndex(AS,v,VVASES,VVASVS) ) ); } 810 811 static if( isOneSymbolPerFieldForAnyAccessString(AS,VVASES,VVASVS) ) 812 { 813 auto opDispatch(string v)() const 814 if( v.length > 1 && oneOfAnyAccessAll(AS,v,VVASES,VVASVS) ) 815 { 816 static string gen() 817 { 818 string[] res; 819 foreach( i, sym; v ) 820 res ~= format( "this.%s[%d]", data, getIndex( AS, ""~sym, VVASES, VVASVS ) ); 821 return res.join(","); 822 } 823 824 mixin( `return Vector!(v.length,T)(` ~ gen() ~ `);` ); 825 } 826 827 auto opDispatch(string v,U)( in U b ) 828 if( v.length > 1 && oneOfAnyAccessAll(AS,v,VVASES,VVASVS) && isCompatibleArrayAccessString(v.length,v) && 829 ( isSpecVector!(v.length,T,U) || ( isDynamicVector!U && is(typeof(T(U.datatype.init))) ) ) ) 830 { 831 static if( b.isDynamic ) enforce( v.length == b.length ); 832 833 static string gen() 834 { 835 string[] res; 836 foreach( i, sym; v ) 837 res ~= format( "this.%s[%d] = T( b[%d] );", data, 838 getIndex( AS, ""~sym, VVASES, VVASVS ), i ); 839 return res.join("\n"); 840 } 841 842 mixin( gen() ); 843 return b; 844 } 845 } 846 } 847 } 848 849 /// 850 unittest 851 { 852 struct NF 853 { 854 ivec2 data; 855 this(E...)( E e ) if( is(typeof(ivec2(e))) ) { data = ivec2(e); } 856 mixin accessByString!( 2,int,"data", "near far|n f" ); 857 } 858 859 auto b = NF(1,100); 860 assert( eq( b.near, b.n ) ); 861 assert( eq( b.far, b.f ) ); 862 863 b.nf = ivec2( 10,20 ); 864 assert( eq( b.near, 10 ) ); 865 assert( eq( b.far, 20 ) ); 866 } 867 868 unittest 869 { 870 auto a = Vector!(0,float).fill(5,1,2); 871 assert( eq( a.length, 5 ) ); 872 assert( eq( a.data, [1,2,1,2,1] ) ); 873 874 auto b = vecD.fill( 10, a, 666 ); 875 assert( eq( b.length, 10 ) ); 876 assert( eq( b.data, [1,2,1,2,1,666,1,2,1,2] ) ); 877 }