1 /** 2 * Several trivial functions and structures 3 */ 4 module iz.sugar; 5 6 import 7 std.traits, std.meta, std.typecons, std.functional; 8 import 9 std.range.primitives: isInputRange, ElementType, ElementEncodingType, 10 isBidirectionalRange; 11 12 /** 13 * Alternative to std.range primitives for arrays. 14 * 15 * The source is never consumed. 16 * The range always verifies isInputRange and isForwardRange. When the source 17 * array element type if not a character type or if the template parameter 18 * assumeDecoded is set to true then the range also verifies 19 * isForwardRange. 20 * 21 * When the source is an array of character and if assumeDecoded is set to false 22 * (the default) then the ArrayRange front type is always dchar because of the 23 * UTF decoding. The parameter can be set to true if the source is known to 24 * contains only SBCs. 25 * 26 * The template parameter infinite allows to turn the range in an infinite range 27 * that loops over the elements. 28 */ 29 struct ArrayRange(T, bool assumeDecoded = false, bool infinite = false) 30 { 31 static if (!isSomeChar!T || assumeDecoded || is(T==dchar)) 32 { 33 private T* _front, _back; 34 private static if(infinite) T* _first; 35 /// 36 this(ref T[] stuff) 37 { 38 _front = stuff.ptr; 39 _back = _front + stuff.length - 1; 40 static if(infinite) _first = _front; 41 } 42 /// 43 @property bool empty() 44 { 45 static if (infinite) 46 return false; 47 else 48 return _front > _back; 49 } 50 /// 51 T front() 52 { 53 return *_front; 54 } 55 /// 56 T back() 57 { 58 return *_back; 59 } 60 /// 61 void popFront() 62 { 63 ++_front; 64 static if (infinite) 65 { 66 if (_front > _back) 67 _front = _first; 68 } 69 } 70 /// 71 void popBack() 72 { 73 --_back; 74 } 75 /// returns a slice of the source, according to front and back. 76 T[] array() 77 { 78 return _front[0 .. _back - _front + 1]; 79 } 80 /// 81 typeof(this) save() 82 { 83 typeof(this) result; 84 result._front = _front; 85 result._back = _back; 86 return result; 87 } 88 } 89 else 90 { 91 92 private: 93 94 import std.utf: decode; 95 size_t _position, _previous, _len; 96 dchar _decoded; 97 T* _front; 98 bool _decode; 99 100 void readNext() 101 { 102 _previous = _position; 103 auto str = _front[0 .. _len]; 104 _decoded = decode(str, _position); 105 } 106 107 public: 108 109 /// 110 this(ref T[] stuff) 111 { 112 _front = stuff.ptr; 113 _len = stuff.length; 114 _decode = true; 115 } 116 /// 117 @property bool empty() 118 { 119 return _position >= _len; 120 } 121 /// 122 dchar front() 123 { 124 if (_decode) 125 { 126 _decode = false; 127 readNext; 128 } 129 return _decoded; 130 } 131 /// 132 void popFront() 133 { 134 if (_decode) readNext; 135 _decode = true; 136 } 137 /// returns a slice of the source, according to front and back. 138 T[] array() 139 { 140 return _front[_previous .. _len]; 141 } 142 /// 143 typeof(this) save() 144 { 145 typeof(this) result; 146 result._position = _position; 147 result._previous = _previous; 148 result._len = _len; 149 result._decoded = _decoded; 150 result._front = _front; 151 result._decode = _decode; 152 return result; 153 } 154 } 155 } 156 157 unittest { 158 auto arr = "bla"; 159 auto rng = ArrayRange!(immutable(char))(arr); 160 assert(rng.array == "bla", rng.array); 161 assert(rng.front == 'b'); 162 rng.popFront(); 163 assert(rng.front == 'l'); 164 rng.popFront(); 165 assert(rng.front == 'a'); 166 rng.popFront(); 167 assert(rng.empty); 168 assert(arr == "bla"); 169 // 170 auto t1 = "é_é"; 171 auto r1 = ArrayRange!(immutable(char))(t1); 172 auto r2 = r1.save; 173 foreach(i; 0 .. 3) r1.popFront(); 174 assert(r1.empty); 175 r1 = r2; 176 assert(r1.front == 'é'); 177 // 178 auto r3 = ArrayRange!(immutable(char),true)(t1); 179 foreach(i; 0 .. 5) r3.popFront(); 180 assert(r3.empty); 181 } 182 183 unittest { 184 ubyte[] src = [1,2,3,4,5]; 185 ubyte[] arr = src.dup; 186 auto rng = ArrayRange!ubyte(arr); 187 ubyte cnt = 1; 188 while (!rng.empty) 189 { 190 assert(rng.front == cnt++); 191 rng.popFront(); 192 } 193 assert(arr == src); 194 auto bck = ArrayRange!ubyte(arr); 195 assert(bck.back == 5); 196 bck.popBack; 197 assert(bck.back == 4); 198 assert(bck.array == [1,2,3,4]); 199 auto sbk = bck.save; 200 bck.popBack; 201 sbk.popBack; 202 assert(bck.back == sbk.back); 203 } 204 205 206 /** 207 * Calls a function according to a probability 208 * 209 * Params: 210 * t = The chance to call, in percentage. 211 * fun = The function to call. It must be a void function. 212 * a = The variadic argument passed to fun. 213 * 214 * Returns: 215 * false if no luck. 216 */ 217 bool pickAndCall(T, Fun, A...)(T t, Fun fun, auto ref A a) 218 if (isNumeric!T && isCallable!Fun && is(ReturnType!Fun == void)) 219 in 220 { 221 static immutable string err = "chance to pick must be in the 0..100 range"; 222 assert(t <= 100, err); 223 assert(t >= 0, err); 224 } 225 do 226 { 227 import std.random: uniform; 228 static immutable T min = 0; 229 static immutable T max = 100; 230 const bool result = uniform!"[]"(min, max) > max - t; 231 if (result) fun(a); 232 return result; 233 } 234 /// 235 @safe unittest { 236 uint cnt; 237 bool test; 238 void foo(uint param0, out bool param1) @safe 239 { 240 cnt += param0; 241 param1 = true; 242 } 243 foreach(immutable i; 0 .. 100) 244 pickAndCall!(double)(75.0, &foo, 1, test); 245 assert(cnt > 25); 246 assert(test); 247 cnt = 0; 248 test = false; 249 foreach(immutable i; 0 .. 100) 250 pickAndCall!(byte)(0, &foo, 1, test); 251 assert(cnt == 0); 252 assert(!test); 253 } 254 255 /** 256 * Pops an input range while a predicate is true. 257 * Consumes the input argument. 258 * 259 * Params: 260 * pred = the predicate. 261 * range = an input range, must be a lvalue. 262 */ 263 void popWhile(alias pred, Range)(ref Range range) 264 if (isInputRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible! 265 (typeof(unaryFun!pred((ElementType!Range).init)), bool)) 266 { 267 import std.range.primitives: front, empty, popFront; 268 alias f = unaryFun!pred; 269 while (!range.empty) 270 { 271 if (!f(range.front)) 272 break; 273 else 274 range.popFront(); 275 } 276 } 277 /// 278 pure @safe unittest { 279 string r0 = "aaaaabcd"; 280 r0.popWhile!"a == 'a'"; 281 assert(r0 == "bcd"); 282 283 static bool lessTwo(T)(T t) 284 { 285 return t < 2; 286 } 287 int[] r1 = [0,1,2,0,1,2]; 288 r1.popWhile!lessTwo; 289 assert(r1 == [2,0,1,2]); 290 291 static bool posLessFive(T)(T t) 292 { 293 return t < 5 && t > 0; 294 } 295 int[] r3 = [2,3,4,-1]; 296 r3.popWhile!posLessFive; 297 assert(r3 == [-1]); 298 int[] r4 = [2,3,4,5]; 299 r4.popWhile!posLessFive; 300 assert(r4 == [5]); 301 } 302 303 /** 304 * Convenience function that calls popWhile() on the input argument 305 * and returns the consumed range to allow function pipelining. 306 * In addition this wrapper accepts rvalues. 307 */ 308 auto dropWhile(alias pred, Range)(auto ref Range range) 309 if (isInputRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible! 310 (typeof(unaryFun!pred((ElementType!Range).init)), bool)) 311 { 312 popWhile!(pred, Range)(range); 313 return range; 314 } 315 /// 316 pure @safe unittest { 317 assert("aaaaabcd".dropWhile!"a == 'a'" == "bcd"); 318 } 319 320 /** 321 * Pops back an input range while a predicate is true. 322 * Consumes the input argument. 323 * 324 * Params: 325 * pred = the predicate. 326 * range = an input range, must be a lvalue. 327 */ 328 void popBackWhile(alias pred, Range)(ref Range range) 329 if (isBidirectionalRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible! 330 (typeof(unaryFun!pred((ElementType!Range).init)), bool)) 331 { 332 import std.range.primitives: back, empty, popBack; 333 alias f = unaryFun!pred; 334 while (!range.empty) 335 { 336 if (!f(range.back)) 337 break; 338 else 339 range.popBack; 340 } 341 } 342 /// 343 pure @safe unittest { 344 string r0 = "bcdaaaa"; 345 r0.popBackWhile!"a == 'a'"; 346 assert(r0 == "bcd"); 347 348 static bool lessTwo(T)(T t) 349 { 350 return t < 2; 351 } 352 int[] r1 = [0,1,2,2,1,0]; 353 r1.popBackWhile!lessTwo; 354 assert(r1 == [0,1,2,2]); 355 356 static bool posLessFive(T)(T t) 357 { 358 return t < 5 && t > 0; 359 } 360 int[] r3 = [-1,2,3,4]; 361 r3.popBackWhile!posLessFive; 362 assert(r3 == [-1]); 363 int[] r4 = [5,2,3,4]; 364 r4.popBackWhile!posLessFive; 365 assert(r4 == [5]); 366 } 367 368 /** 369 * Convenience function that calls popBackWhile() on the input argument 370 * and returns the consumed range to allow function pipelining. 371 * In addition this wrapper accepts rvalues. 372 */ 373 auto dropBackWhile(alias pred, Range)(auto ref Range range) 374 if (isBidirectionalRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible! 375 (typeof(unaryFun!pred((ElementType!Range).init)), bool)) 376 { 377 popBackWhile!(pred, Range)(range); 378 return range; 379 } 380 /// 381 pure @safe unittest { 382 assert("abcdefgh".dropBackWhile!"a > 'e'" == "abcde"); 383 } 384 385 /** 386 * Returns a lazy input range that alterntively returns the state of one of two 387 * sub-ranges. 388 * 389 * Similar to std.range roundRobin() or chain() except that the resulting range 390 * is considered as empty when one of the sub range is consumed. 391 * 392 * Params: 393 * flip = the first input range. 394 * flop = the second input range. 395 */ 396 auto flipFlop(R1, R2)(auto ref R1 flip, auto ref R2 flop) 397 if (isInputRange!R1 && isInputRange!R2 && is(ElementType!R1 == ElementType!R2)) 398 { 399 import std.range.primitives: front, empty, popFront; 400 struct FlipFlop 401 { 402 private bool _takeFlop; 403 404 /// 405 bool empty() 406 { 407 return (flip.empty && !_takeFlop) | (_takeFlop && flop.empty); 408 } 409 /// 410 auto front() 411 { 412 final switch (_takeFlop) 413 { 414 case false: return flip.front; 415 case true: return flop.front; 416 } 417 } 418 /// 419 void popFront() 420 { 421 _takeFlop = !_takeFlop; 422 final switch (_takeFlop) 423 { 424 case false: return flop.popFront(); 425 case true: return flip.popFront(); 426 } 427 } 428 } 429 FlipFlop ff; 430 return ff; 431 } 432 /// 433 pure @safe unittest { 434 import std.array: array; 435 assert(flipFlop([0,2,4],[1,3,5]).array == [0,1,2,3,4,5]); 436 assert(flipFlop([0,2],[1,3,5]).array == [0,1,2,3]); 437 assert(flipFlop([0,2,4],[1,3]).array == [0,1,2,3,4]); 438 int[] re = []; 439 assert(flipFlop([0], re).array == [0]); 440 assert(flipFlop(re, re).array == []); 441 assert(flipFlop(re, [0]).array == []); 442 } 443 444 /** 445 * Returns a lazy input range that takes from the input while a predicate is 446 * verified and the input is not empty. 447 * 448 * Params: 449 * pred = the predicate. 450 * range = an input range, only consumed when passed by reference. 451 */ 452 auto takeWhile(alias pred, Range)(auto ref Range range) 453 if (isInputRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible! 454 (typeof(unaryFun!pred((ElementType!Range).init)), bool)) 455 { 456 alias f = unaryFun!pred; 457 import std.range.primitives: front, empty, popFront; 458 struct Taker 459 { 460 /// 461 bool empty() 462 { 463 return range.empty || !f(range.front); 464 } 465 /// 466 void popFront() 467 { 468 range.popFront(); 469 } 470 /// 471 auto front() 472 { 473 return range.front; 474 } 475 } 476 Taker result; 477 return result; 478 } 479 /// 480 pure @safe unittest { 481 import std.range: array; 482 import std.ascii: isDigit; 483 auto r = "012A"; 484 assert(takeWhile!((a) => isDigit(a))(r).array == "012"); 485 assert(r == "A"); 486 assert(takeWhile!((a) => isDigit(a))(r).array == ""); 487 assert(takeWhile!((a) => isDigit(a))("").array == ""); 488 } 489 490 /** 491 * Returns a lazy input range that takes from the input tail while a 492 * predicate is verified and the input is not empty. 493 * 494 * Params: 495 * pred = the predicate. 496 * range = an bidirectional range, only consumed when passed by reference. 497 */ 498 auto takeBackWhile(alias pred, Range)(auto ref Range range) 499 if (isBidirectionalRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible! 500 (typeof(unaryFun!pred((ElementType!Range).init)), bool)) 501 { 502 alias f = unaryFun!pred; 503 import std.range.primitives: back, empty, popBack; 504 struct Taker 505 { 506 /// 507 bool empty() 508 { 509 return range.empty || !f(range.back); 510 } 511 /// 512 void popFront() 513 { 514 range.popBack; 515 } 516 /// 517 auto front() 518 { 519 return range.back; 520 } 521 } 522 Taker result; 523 return result; 524 } 525 /// 526 pure @safe unittest { 527 import std.range: array; 528 import std.ascii: isDigit; 529 auto r = "A123"; 530 assert(takeBackWhile!((a) => isDigit(a))(r).array == "321"); 531 assert(r == "A"); 532 assert(takeBackWhile!((a) => isDigit(a))(r).array == ""); 533 assert(takeBackWhile!((a) => isDigit(a))("").array == ""); 534 } 535 536 /** Indicates how many elements of a range are different from the default 537 * element value. 538 * 539 * Params: 540 * range = An input range. The elements must be mutable and initializable. 541 * Narrow srings are not considered as validate input parameter. 542 * 543 * Returns: 544 * A number equal to the count of elements that are different from their 545 * initializer. 546 */ 547 size_t mutatedCount(Range)(Range range) 548 if (isInputRange!Range && is(typeof((ElementType!Range).init)) 549 && isMutable!(ElementType!Range) && !isNarrowString!Range) 550 { 551 import std.range.primitives: front, empty, popFront; 552 553 size_t result; 554 const(ElementType!Range) noone = (ElementType!Range).init; 555 while (!range.empty) 556 { 557 result += ubyte(range.front != noone); 558 range.popFront(); 559 } 560 return result; 561 } 562 /// 563 unittest { 564 int[] i = [0,0,1]; 565 assert(i.mutatedCount == 1); 566 assert(i[0..$-1].mutatedCount == 0); 567 568 string[] s = ["","a"]; 569 assert(s.mutatedCount == 1); 570 571 dchar[] dc = [dchar.init, 'g']; 572 assert(dc.mutatedCount == 1); 573 574 class Foo {} 575 Foo[] f = new Foo[](8); 576 assert(f.mutatedCount == 0); 577 f[0] = new Foo; 578 f[1] = new Foo; 579 assert(f.mutatedCount == 2); 580 581 // w/char.init leads to decoding invalid UTF8 sequence 582 static assert(!is(typeof(mutatedCount!(char[])))); 583 static assert(!is(typeof(mutatedCount!(wchar[])))); 584 585 static assert(is(typeof(mutatedCount!(dchar[])))); 586 } 587 588 /** 589 * Allows to pass always a parameter as value even if it would be accepted 590 * as reference. 591 */ 592 auto rValue(T)(auto ref T t) 593 { 594 return t; 595 } 596 /// 597 unittest { 598 void foo(T)(ref T t){} 599 uint a; 600 static assert(is(typeof(foo(a)))); 601 static assert(!is(typeof(foo(a.rValue)))); 602 } 603 604 /** 605 * Compares two integral values with additional static checkings. 606 * 607 * If the comparison mixes signed and unsigned operands then the function tries 608 * to widen the unsigned operand to perform a valid comparison, otherwise 609 * a DMD-style warning is emitted. 610 * 611 * Params: 612 * op = The comparison operator, must be either >, < , <= or >=. Equality 613 * is also allowed even if this is always a transparent operation. 614 * lhs = The left operand, an integer. 615 * rhs = The right operand, an integer. 616 * 617 * Returns: 618 * A bool, the comparison result. 619 */ 620 bool compare(string op, L, R, string fname = __FILE__, int line = __LINE__) 621 (auto ref L lhs, auto ref R rhs) 622 if ((isIntegral!R && isIntegral!L) && op == "<" || op == ">" || op == "<=" || 623 op == ">=" || op == "==" || op == "!=") 624 { 625 alias LT = Unqual!L; 626 alias RT = Unqual!R; 627 628 // transparent 629 static if (is(LT == RT) || op == "==" || op == "!=") 630 { 631 mixin("return lhs" ~ op ~ "rhs;"); 632 } 633 else 634 { 635 enum err = fname ~ "(" ~ line.stringof ~ "): "; 636 enum wer = "warning, signed and unsigned comparison, the unsigned operand has been widened"; 637 638 template Widened(T) 639 { 640 static if (is(T==ubyte)) 641 alias Widened = short; 642 else static if (is(T==ushort)) 643 alias Widened = int; 644 else static if (is(T==uint)) 645 alias Widened = long; 646 } 647 648 // widen unsigned to bigger signed 649 static if (isSigned!LT && !isSigned!RT && RT.sizeof < 8) 650 { 651 version (D_Warnings) pragma(msg, err ~ wer); 652 Widened!RT widenedRhs = rhs; 653 mixin("return lhs" ~ op ~ "widenedRhs;"); 654 } 655 else static if (isSigned!RT && !isSigned!LT && LT.sizeof < 8) 656 { 657 version (D_Warnings) pragma(msg, err ~ wer); 658 Widened!LT widenedLhs = lhs; 659 mixin("return widenedLhs" ~ op ~ "rhs;"); 660 } 661 // not fixable by widening 662 else 663 { 664 pragma(msg, err ~ "warning, comparing a " ~ L.stringof ~ " with a " 665 ~ R.stringof ~ " may result into wrong results"); 666 mixin("return lhs" ~ op ~ "rhs;"); 667 } 668 } 669 } 670 /// 671 pure @safe @nogc nothrow unittest { 672 int a = -1; uint b; 673 assert(a > b); // wrong result 674 assert(compare!">"(a,b) == false); // fixed by operand widening 675 assert(b < a); // wrong result 676 assert(compare!"<"(b,a) == false); // fixed by operand widening 677 678 long aa = -1; ulong bb; 679 assert(aa > bb); // wrong result 680 assert(compare!">"(aa,bb) == true); // not statically fixable 681 assert(bb < aa); // wrong result 682 assert(compare!"<"(bb,aa) == true); // not statically fixable 683 684 assert(compare!"!="(bb,aa) == true); // test for equality is always transparent OP 685 686 immutable long aaa = -1; const ulong bbb; 687 assert(compare!">"(aaa,bbb) == true); 688 } 689 690 /** 691 * Throws a static exception, suitable for @nogc functions. 692 */ 693 @nogc @safe 694 void throwStaticEx(T, string file = __FILE__, size_t line = __LINE__)() 695 { 696 static const e = new T(file, line); 697 throw e; 698 } 699 700 /// ditto 701 @nogc @safe 702 void throwStaticEx(string message, string file = __FILE__, size_t line = __LINE__)() 703 { 704 static const e = new Exception(message, file, line); 705 throw e; 706 } 707 708 /** 709 * Sets the context and the function of a delegate. 710 * 711 * Params: 712 * T = The type of the delegate. 713 * t = The delegate to set. 714 * context = The context pointer, e.g a pointer to a struct or a class instance. 715 * code = The pointer to the static function. 716 */ 717 void setDelegate(T, FT)(ref T t, void* context, FT code) 718 if (is(T == delegate) && is(FT == typeof(T.funcptr))) 719 { 720 t.ptr = context; 721 t.funcptr = code; 722 } 723 /// 724 unittest { 725 struct Foo 726 { 727 bool fun(){return true;} 728 } 729 Foo foo; 730 bool delegate() atFun; 731 atFun.setDelegate(&foo, &Foo.fun); 732 assert(atFun()); 733 } 734 735 /** 736 * Sets the context and the function of a new delegate. 737 * 738 * Params: 739 * T = The type of the delegate. 740 * t = The delegate to set. 741 * context = The context pointer, e.g a pointer to a struct or a class instance. 742 * code = The pointer to the static function. 743 * 744 * Returns: 745 * A new delegate of type T. 746 */ 747 auto getDelegate(FT)(void* context, FT code) 748 if (is(PointerTarget!FT == function)) 749 { 750 import std.array: replace; 751 enum type = "alias T = " ~ FT.stringof.replace("function", "delegate") ~ ";"; 752 mixin(type); 753 T t; 754 t.ptr = context; 755 t.funcptr = code; 756 return t; 757 } 758 /// 759 unittest { 760 struct Foo 761 { 762 bool fun(){return true;} 763 } 764 Foo foo; 765 bool delegate() atFun = getDelegate(&foo, &Foo.fun); 766 assert(atFun()); 767 } 768 769 /** 770 * The delegate union is a conveniant way to setup non gc delegates that 771 * are compatible with D delegates. 772 */ 773 union Delegate(FT) 774 if (is(PointerTarget!FT == function)) 775 { 776 /// Defines the delegate layout as defined in the D ABI 777 struct DgMembers 778 { 779 void* ptr; 780 FT funcptr; 781 } 782 783 //// The delegates members; 784 DgMembers members; 785 alias members this; 786 787 import std.array: replace; 788 enum type = "alias T = " ~ FT.stringof.replace("function", "delegate") ~ ";"; 789 mixin(type); 790 791 /// Allows to use this union as a true D delegate. 792 T dg; 793 794 /// Helper to call the delegate without accessing `dg`. 795 auto opCall(A...)(A a) 796 { 797 return dg(a); 798 } 799 } 800 /// 801 unittest { 802 struct Foo 803 { 804 bool fun(){return true;} 805 } 806 Foo foo; 807 Delegate!(typeof(&Foo.fun)) atFun; 808 atFun.ptr = &foo, 809 atFun.funcptr = &Foo.fun, 810 assert(atFun()); 811 } 812 813 /** 814 * Safely cast a value of a type to another, if both have the same size. 815 * 816 * Unlike `bruteCast`, the same location si not shared between the 817 * source and the target and no pointer is used. 818 * This function is inspired by http://www.forwardscattering.org/post/27 819 */ 820 template bitCast(T, S) 821 if (T.sizeof == S.sizeof 822 && !is(S == T) 823 && !(is(S== float) & (size_t.sizeof == 4)) 824 && !is(S == class) && !is(T == class) 825 && !is(S == interface) && !is(T == interface)) 826 { 827 private union BitCaster 828 { 829 S ss; 830 T tt; 831 } 832 833 static assert(BitCaster.sizeof == S.sizeof); 834 835 pragma(inline, true) 836 T bitCast(auto ref S s) 837 { 838 BitCaster bt; 839 bt.ss = s; 840 return bt.tt; 841 } 842 } 843 /// 844 pure nothrow @safe unittest { 845 assert(bitCast!int(1.0f) == 0x3f800000); 846 version (LittleEndian) 847 assert(bitCast!(ubyte[2])(ushort(0x1234)) == [0x34, 0x12]); 848 else 849 assert(bitCast!(ubyte[2])(ushort(0x1234)) == [0x12, 0x34]); 850 } 851 852 /// ditto 853 template bitCast(T, S) 854 if (T.sizeof == S.sizeof && is(S == float) 855 && !is(T == class) && !is(T == interface)) 856 { 857 T bitCast(S[1] source...) pure 858 { 859 // S[1]: prevent the source to be loaded in ST(0) 860 // and any normalization to happen. 861 asm @trusted @nogc pure nothrow 862 { 863 naked; 864 ret; 865 } 866 } 867 } 868 869 /// Deep iteration mode 870 enum IdMode 871 { 872 depth, 873 breadth 874 } 875 876 /** 877 * Iterates a tree-like structure that exposes an input range interface and calls 878 * each element with a function. 879 * 880 * Params: 881 * Fun = The function called for each element. When its return type is bool, 882 * and if it returns true, the iterations are stopped. 883 * member = The name of the member that gives the real Range. 884 * mode = The iteration mode (breadth-first or depth-first). 885 * range = The root element. 886 * a = The variadic parameters passed to Fun (after the element). 887 * Returns: 888 * True if the iterations have stopped, false otherwise. 889 */ 890 bool deepIterate(alias Fun, string member = "", IdMode mode = IdMode.breadth, 891 Range, A...)(Range range, auto ref A a) 892 { 893 static if (!member.length) 894 { 895 alias Rng = Range; 896 alias M = void; 897 } 898 else 899 { 900 mixin("alias M = typeof(Range." ~ member ~ ");"); 901 static assert(__traits(hasMember, Range, member), 902 "invalid Range member, Range has no member named '" ~ member ~ "'"); 903 } 904 enum callable = isCallable!M; 905 static if (callable) 906 alias Rng = ReturnType!M; 907 static assert(isInputRange!Rng && is(ElementType!Rng == Range), 908 "invalid deepIterate Range"); 909 910 static if (is(ReturnType!Fun)) 911 { 912 alias R = ReturnType!Fun; 913 enum funIsPred = is(R == bool); 914 } 915 else enum funIsPred = false; 916 917 bool result; 918 919 enum callWithFront = 920 q{ 921 static if (funIsPred) 922 result = Fun(range, a); 923 else 924 Fun(range, a); 925 if (result) 926 return true; 927 }; 928 929 static if (!__traits(hasMember, range, "front")) 930 { 931 import std.range.primitives: front, empty, popFront; 932 } 933 934 static if (mode == IdMode.breadth) 935 mixin(callWithFront); 936 937 static if (!member.length) 938 alias items = range; 939 else static if (callable) 940 mixin("auto items = range." ~ member ~ ";"); 941 else 942 mixin("alias items = range." ~ member ~ ";"); 943 944 while (!items.empty) 945 { 946 result = deepIterate!(Fun, member, mode, Range, A)(items.front, a); 947 if (result) 948 break; 949 items.popFront(); 950 } 951 952 static if (mode == IdMode.depth) 953 mixin(callWithFront); 954 955 return result; 956 } 957 /// 958 unittest { 959 // creates a tree 960 Item root = new Item; 961 root.populate; 962 root[0].populate; 963 root[1].populate; 964 965 int cnt, a; 966 967 // count the population 968 deepIterate!((e) => ++cnt)(root); 969 assert(cnt == 7); 970 971 // previous content is consumed 972 root.populate; 973 root[0].populate; 974 root[1].populate; 975 976 // the delegate result is used to stop the iteration 977 deepIterate!((Item e, ref int p){++p; --cnt; return cnt == 4;})(root, a); 978 assert(cnt == 4); 979 assert(a == 3); 980 } 981 982 version (unittest) private class Item 983 { 984 alias children this; 985 Item[] children; 986 void populate() 987 { 988 children.length = 2; 989 children[0] = new Item; 990 children[1] = new Item; 991 assert(children.length == 2); 992 } 993 } 994 995 // unittest 996 // { 997 // import iz.containers: ObjectTreeItem; 998 // import iz.memory: construct, destruct; 999 // ObjectTreeItem root = construct!ObjectTreeItem; 1000 // ObjectTreeItem c1 = root.addNewChild!ObjectTreeItem; 1001 // ObjectTreeItem c2 = root.addNewChild!ObjectTreeItem; 1002 // ObjectTreeItem c1c1 = c1.addNewChild!ObjectTreeItem; 1003 // ObjectTreeItem c1c2 = c1.addNewChild!ObjectTreeItem; 1004 // ObjectTreeItem c2c1 = c2.addNewChild!ObjectTreeItem; 1005 // ObjectTreeItem c2c2 = c2.addNewChild!ObjectTreeItem; 1006 1007 // int cnt, a; 1008 // deepIterate!((e) => ++cnt, "children")(root); 1009 // assert(cnt == 7); 1010 1011 // root.deleteChildren; 1012 // destruct(root); 1013 // } 1014 1015 /** 1016 * Allows to call recursively the function being executed. 1017 * 1018 * Params: 1019 * a = the parameters expected by the function. 1020 * Examples: 1021 * 1022 * --- 1023 * long factorial(long a) 1024 * { 1025 * if (a <= 1) 1026 * return a; 1027 * else 1028 * return a * recursion(a-1); 1029 * } 1030 * --- 1031 * 1032 * Returns: 1033 * The same as the function being executed. 1034 */ 1035 auto recursion(string Fun = __FUNCTION__ , A...)(auto ref A a) 1036 { 1037 import std.typecons: tuple; 1038 mixin("return " ~ Fun ~ "(" ~ a.stringof ~ "[0..$]);"); 1039 } 1040 1041 /** 1042 * Used the annotate the member functions that wrap other member functions. 1043 * Each instance must specify aither the type, the instance and the name of the 1044 * function that's wrapped or the name of a context-free function. 1045 * Each string must be colon-separated. 1046 */ 1047 struct Wrap{string[] targets;} 1048 /// 1049 unittest { 1050 struct Foo 1051 { 1052 @Wrap(["Type:instance:name", "freeFunction"]) 1053 void foo(){} 1054 } 1055 } 1056 1057 /** 1058 * Scans the method wrapped by the caller. 1059 * 1060 * Params: 1061 * f = The caller' s name. Autodetected. 1062 * returns = The variables that get the result of each wrapped function. 1063 * They must be references. 1064 * 1065 * Returns: 1066 * A string that has to be mixed in the caller's body. 1067 */ 1068 string applyWrap(string f = __FUNCTION__, R...)(ref R returns) 1069 { 1070 static assert(R.length == 0, "returns are not implemented yet"); 1071 1072 import std.array: array; 1073 import std.algorithm.iteration: splitter; 1074 import std.meta: aliasSeqOf; 1075 import std.range: iota; 1076 import std.string: join; 1077 import std.traits: getUDAs, Parameters, ParameterIdentifierTuple, ReturnType; 1078 1079 alias attrbs = getUDAs!(mixin(f), Wrap); 1080 alias params = Parameters!(mixin(f)); 1081 1082 string result; 1083 1084 foreach(i; aliasSeqOf!(iota(0, attrbs.length))) 1085 { 1086 foreach(j; aliasSeqOf!(iota(0, attrbs[i].targets.length))) 1087 { 1088 enum s = splitter(attrbs[i].targets[j], ":").array; 1089 1090 if (s.length != 3 && s.length != 1) 1091 { 1092 assert(0, "Invalid Type:instance:method specifier: \n" 1093 ~ attrbs[i].targets[j]); 1094 } 1095 static if (s.length == 3) 1096 { 1097 static assert (__traits(hasMember, mixin(s[0]), s[2]), s[0] ~ 1098 " has no member named " ~ s[2]); 1099 enum typeDotMethod = s[0] ~ "." ~ s[2]; 1100 enum instanceDotMethod = s[1] ~ "." ~ s[2]; 1101 alias p = Parameters!(mixin(typeDotMethod)); 1102 alias r = ReturnType!(mixin(typeDotMethod)); 1103 } 1104 else 1105 { 1106 alias p = Parameters!(mixin(s[0])); 1107 alias r = ReturnType!(mixin(s[0])); 1108 } 1109 1110 static if (!p.length) 1111 { 1112 static if (s.length == 3) 1113 result ~= instanceDotMethod ~ ";"; 1114 else 1115 result ~= s[0] ~ ";"; 1116 } 1117 else static if (is(p == params)) 1118 { 1119 static if (s.length == 3) 1120 { 1121 alias n = ParameterIdentifierTuple!(mixin(typeDotMethod)); 1122 result ~= instanceDotMethod ~ "(" ~ [n[0..$]].join(", ") ~ ");"; 1123 } 1124 else 1125 { 1126 alias n = ParameterIdentifierTuple!(mixin(s[0])); 1127 result ~= s[0] ~ "(" ~ [n[0..$]].join(", ") ~ ");"; 1128 } 1129 } 1130 else static assert(0, "incompatible parameters: \n" 1131 ~ "got :" ~ p.stringof ~ "\n" 1132 ~ "expected:" ~ params.stringof); 1133 } 1134 } 1135 return result; 1136 } 1137 /// 1138 version (none) unittest { 1139 static bool int42, int8, ffree1, ffree2; 1140 1141 static struct Inner 1142 { 1143 void foo(int p0, int p1){int42 = true; int8 = true;} 1144 void bar() {ffree1 = true;} 1145 } 1146 1147 static void freeFunc() 1148 { 1149 ffree2 = true; 1150 } 1151 1152 static struct Composed 1153 { 1154 Inner inner; 1155 1156 @Wrap(["Inner:inner:foo", "Inner:inner:bar", "freeFunc"]) 1157 void foo(int p0, int p1) 1158 { 1159 mixin(applyWrap()); 1160 } 1161 } 1162 1163 static Composed c; 1164 c.foo(42,8); 1165 assert(int42 & int8 & ffree1 & ffree2); 1166 }