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