1 /++ 2 Containers. 3 4 Example: 5 --- 6 { 7 Buffer!string buffer; 8 9 buffer.put("abc"); 10 buffer.put("def"); 11 assert(!buffer.empty); 12 assert(buffer.front == "abc"); 13 buffer.popFront(); 14 assert(buffer.front == "def"); 15 buffer.popFront(); 16 assert(buffer.empty); 17 } 18 { 19 Buffer!(char, Yes.dynamic, 3) buffer; 20 21 assert(!buffer.buf.length); 22 buffer ~= 'a'; 23 assert(buffer.buf.length == 3); 24 buffer ~= 'b'; 25 buffer ~= 'c'; 26 assert(buffer.length == 3); 27 buffer ~= 'd'; 28 assert(buffer.buf.length > 3); 29 assert(buffer[0..5] == "abcd"); 30 buffer.clear(); 31 assert(buffer.empty); 32 } 33 { 34 RehashingAA!(int[string]) aa; 35 aa.minimumNeededForRehash = 2; 36 37 aa["abc"] = 123; 38 aa["def"] = 456; 39 assert((aa.newKeysSinceLastRehash == 2), aa.newKeysSinceLastRehash.to!string); 40 assert((aa.numRehashes == 0), aa.numRehashes.to!string); 41 aa["ghi"] = 789; 42 assert((aa.numRehashes == 1), aa.numRehashes.to!string); 43 assert((aa.newKeysSinceLastRehash == 0), aa.newKeysSinceLastRehash.to!string); 44 aa.rehash(); 45 assert((aa.numRehashes == 2), aa.numRehashes.to!string); 46 47 auto realAA = cast(int[string])aa; 48 assert("abc" in realAA); 49 assert("def" in realAA); 50 51 auto alsoRealAA = aa.aaOf; 52 assert("ghi" in realAA); 53 assert("jkl" !in realAA); 54 55 auto aa2 = aa.dup; 56 aa2["jkl"] = 123; 57 assert("jkl" in aa2); 58 assert("jkl" !in aa); 59 } 60 { 61 MutexedAA!(string[int]) aa; 62 aa.setup(); // important! 63 64 aa[1] = "one"; 65 aa[2] = "two"; 66 aa[3] = "three"; 67 68 auto hasOne = aa.has(1); 69 assert(hasOne); 70 assert(aa[1] == "one"); 71 72 assert(aa[2] == "two"); 73 74 auto three = aa.get(3); 75 assert(three == "three"); 76 77 auto four = aa.get(4, "four"); 78 assert(four == "four"); 79 80 auto five = aa.require(5, "five"); 81 assert(five == "five"); 82 assert(aa[5] == "five"); 83 84 auto keys = aa.keys; 85 assert(keys.canFind(1)); 86 assert(keys.canFind(5)); 87 assert(!keys.canFind(6)); 88 89 auto values = aa.values; 90 assert(values.canFind("one")); 91 assert(values.canFind("four")); 92 assert(!values.canFind("six")); 93 94 aa.rehash(); 95 } 96 --- 97 98 Copyright: [JR](https://github.com/zorael) 99 License: [Boost Software License 1.0](https://www.boost.org/users/license.html) 100 101 Authors: 102 [JR](https://github.com/zorael) 103 +/ 104 module lu.container; 105 106 private: 107 108 import std.typecons : Flag, No, Yes; 109 110 public: 111 112 113 // Buffer 114 /++ 115 Simple buffer/queue for storing and fetching items of any type `T`. 116 Does not use manual memory allocation. 117 118 It can use a static array internally to store elements on the stack, which 119 imposes a hard limit on how many items can be added, or a dynamic heap one 120 with a resizable buffer. 121 122 Example: 123 --- 124 Buffer!(string, No.dynamic, 16) buffer; 125 126 buffer.put("abc"); 127 buffer ~= "def"; 128 assert(!buffer.empty); 129 assert(buffer.front == "abc"); 130 buffer.popFront(); 131 assert(buffer.front == "def"); 132 buffer.popFront(); 133 assert(buffer.empty); 134 --- 135 136 Params: 137 T = Buffer item type. 138 dynamic = Whether to use a dynamic array whose size can be grown at 139 runtime, or to use a static array with a fixed size. Trying to add 140 more elements than there is room for will cause an assert. 141 Defaults to `No.dynamic`; a static array. 142 originalSize = How many items to allocate space for. If `No.dynamic` was 143 passed it will assert if you attempt to store anything past this amount. 144 +/ 145 struct Buffer(T, Flag!"dynamic" dynamic = No.dynamic, size_t originalSize = 128) 146 { 147 pure nothrow: 148 static if (dynamic) 149 { 150 /++ 151 By how much to grow the buffer when we reach the end of it. 152 +/ 153 private enum growthFactor = 1.5; 154 155 /++ 156 Internal buffer dynamic array. 157 +/ 158 T[] buf; 159 160 /++ 161 Variable buffer size. 162 +/ 163 size_t bufferSize; 164 } 165 else 166 { 167 /++ 168 Internal buffer static array. 169 +/ 170 T[bufferSize] buf; 171 172 /++ 173 Static buffer size. 174 +/ 175 alias bufferSize = originalSize; 176 } 177 178 /++ 179 Current position in the array. 180 +/ 181 ptrdiff_t pos; 182 183 /++ 184 Position of last entry in the array. 185 +/ 186 ptrdiff_t end; 187 188 static if (dynamic) 189 { 190 // put 191 /++ 192 Append an item to the end of the buffer. 193 194 If it would be put beyond the end of the buffer, it will be resized to fit. 195 196 Params: 197 more = Item to add. 198 +/ 199 void put(/*const*/ T more) pure @safe nothrow 200 { 201 if (end == bufferSize) 202 { 203 bufferSize = !bufferSize ? originalSize : cast(size_t)(bufferSize * growthFactor); 204 buf.length = bufferSize; 205 } 206 207 buf[end++] = more; 208 } 209 } 210 else 211 { 212 // put 213 /++ 214 Append an item to the end of the buffer. 215 216 If it would be put beyond the end of the buffer, it will assert. 217 218 Params: 219 more = Item to add. 220 +/ 221 void put(/*const*/ T more) pure @safe nothrow @nogc 222 in ((end < bufferSize), '`' ~ typeof(this).stringof ~ "` buffer overflow") 223 { 224 buf[end++] = more; 225 } 226 } 227 228 static if (dynamic) 229 { 230 // reserve 231 /++ 232 Reserves enough room for the specified number of elements. If there 233 is already enough room, nothing is done. Otherwise the buffer is grown. 234 235 Params: 236 reserveSize = Number of elements to reserve size for. 237 +/ 238 void reserve(const size_t reserveSize) pure @safe nothrow 239 { 240 if (bufferSize < reserveSize) 241 { 242 bufferSize = reserveSize; 243 buf.length = bufferSize; 244 } 245 } 246 } 247 248 // opOpAssign 249 /++ 250 Implements `buf ~= someT` (appending) by wrapping `put`. 251 252 Params: 253 op = Operation type, here specialised to "`~`". 254 more = Item to add. 255 +/ 256 void opOpAssign(string op : "~")(/*const*/ T more) pure @safe nothrow 257 { 258 return put(more); 259 } 260 261 // front 262 /++ 263 Fetches the item at the current position of the buffer. 264 265 Returns: 266 An item T. 267 +/ 268 ref auto front() inout pure @safe nothrow @nogc 269 in ((end > 0), '`' ~ typeof(this).stringof ~ "` buffer underrun") 270 { 271 return buf[pos]; 272 } 273 274 // popFront 275 /++ 276 Advances the current position to the next item in the buffer. 277 +/ 278 void popFront() pure @safe nothrow @nogc 279 { 280 if (++pos == end) reset(); 281 } 282 283 // length 284 /++ 285 Returns what amounts to the current length of the buffer; the distance 286 between the current position `pos` and the last element `end`. 287 288 Returns: 289 The buffer's current length. 290 +/ 291 auto length() const inout 292 { 293 return (end - pos); 294 } 295 296 // empty 297 /++ 298 Returns whether or not the container is considered empty. 299 300 Mind that the buffer may well still contain old contents. Use `clear` 301 to zero it out. 302 303 Returns: 304 `true` if there are items available to get via `front`, 305 `false` if not. 306 +/ 307 auto empty() const inout 308 { 309 return (end == 0); 310 } 311 312 // reset 313 /++ 314 Resets the array positions, effectively soft-emptying the buffer. 315 316 The old elements' values are still there, they will just be overwritten 317 as the buffer is appended to. 318 +/ 319 void reset() pure @safe nothrow @nogc 320 { 321 pos = 0; 322 end = 0; 323 } 324 325 // clear 326 /++ 327 Zeroes out the buffer's elements, getting rid of old contents. 328 +/ 329 void clear() pure @safe nothrow @nogc 330 { 331 reset(); 332 buf[] = T.init; 333 } 334 } 335 336 /// 337 unittest 338 { 339 { 340 Buffer!(bool, No.dynamic, 4) buffer; 341 342 assert(buffer.empty); 343 buffer.put(true); 344 buffer.put(false); 345 assert(buffer.length == 2); 346 buffer.put(true); 347 buffer.put(false); 348 349 assert(!buffer.empty); 350 assert(buffer.front == true); 351 buffer.popFront(); 352 assert(buffer.front == false); 353 buffer.popFront(); 354 assert(buffer.front == true); 355 buffer.popFront(); 356 assert(buffer.front == false); 357 buffer.popFront(); 358 assert(buffer.empty); 359 assert(buffer.buf == [ true, false, true, false ]); 360 buffer.put(false); 361 assert(buffer.buf == [ false, false, true, false ]); 362 buffer.reset(); 363 assert(buffer.empty); 364 buffer.clear(); 365 assert(buffer.buf == [ false, false, false, false ]); 366 } 367 { 368 Buffer!(string, No.dynamic, 4) buffer; 369 370 assert(buffer.empty); 371 buffer.put("abc"); 372 buffer.put("def"); 373 buffer.put("ghi"); 374 375 assert(!buffer.empty); 376 assert(buffer.front == "abc"); 377 buffer.popFront(); 378 assert(buffer.front == "def"); 379 buffer.popFront(); 380 buffer.put("JKL"); 381 assert(buffer.front == "ghi"); 382 buffer.popFront(); 383 assert(buffer.front == "JKL"); 384 buffer.popFront(); 385 assert(buffer.empty); 386 assert(buffer.buf == [ "abc", "def", "ghi", "JKL" ]); 387 buffer.put("MNO"); 388 assert(buffer.buf == [ "MNO", "def", "ghi", "JKL" ]); 389 buffer.clear(); 390 assert(buffer.buf == [ string.init, string.init, string.init, string.init ]); 391 } 392 { 393 Buffer!(char, No.dynamic, 64) buffer; 394 buffer ~= 'a'; 395 buffer ~= 'b'; 396 buffer ~= 'c'; 397 assert(buffer.buf[0..3] == "abc"); 398 399 foreach (char_; buffer) 400 { 401 assert((char_ == 'a') || (char_ == 'b') || (char_ == 'c')); 402 } 403 } 404 { 405 Buffer!(int, Yes.dynamic, 3) buffer; 406 assert(!buffer.buf.length); 407 buffer ~= 1; 408 assert(buffer.buf.length == 3); 409 buffer ~= 2; 410 buffer ~= 3; 411 assert(buffer.front == 1); 412 buffer.popFront(); 413 assert(buffer.front == 2); 414 buffer.popFront(); 415 assert(buffer.front == 3); 416 buffer.popFront(); 417 assert(buffer.empty); 418 buffer.reserve(64); 419 assert(buffer.buf.length == 64); 420 buffer.reserve(63); 421 assert(buffer.buf.length == 64); 422 } 423 { 424 Buffer!(char, No.dynamic, 4) buffer; 425 buffer ~= 'a'; 426 buffer ~= 'b'; 427 buffer ~= 'c'; 428 buffer ~= 'd'; 429 assert(buffer.buf == "abcd"); 430 assert(buffer.length == 4); 431 buffer.reset(); 432 assert(buffer.buf == "abcd"); 433 buffer.clear(); 434 assert(buffer.buf == typeof(buffer.buf).init); 435 } 436 } 437 438 439 // CircularBuffer 440 /++ 441 Simple circular-ish buffer for storing items of type `T` that discards elements 442 when the maximum size is reached. Does not use manual memory allocation. 443 444 It can use a static array internally to store elements on the stack, which 445 imposes a hard limit on how many items can be added, or a dynamic heap one 446 with a resizable buffer. 447 448 Example: 449 --- 450 CircularBuffer!(int, Yes.dynamic) buf; 451 buf.resize(3); 452 buf.put(1); 453 buf.put(2); 454 buf.put(3); 455 but.put(4); 456 assert(buf.front == 4); 457 assert(buf.buf == [ 4, 2, 3 ]); 458 --- 459 460 Params: 461 T = Buffer item type. 462 dynamic = Whether to use a dynamic array whose size can be grown at 463 runtime, or to use a static array with a fixed size. Trying to add 464 more elements than there is room for will wrap around and discard elements. 465 Defaults to `No.dynamic`; a static buffer. 466 originalSize = How many items to allocate space for in the case of a 467 static array. 468 +/ 469 struct CircularBuffer(T, Flag!"dynamic" dynamic = No.dynamic, size_t originalSize = 16) 470 if (originalSize > 1) 471 { 472 private: 473 static if (dynamic) 474 { 475 // buf 476 /++ 477 Internal buffer dynamic array. 478 +/ 479 T[] buf; 480 } 481 else 482 { 483 // buf 484 /++ 485 Internal buffer static array. 486 +/ 487 T[originalSize] buf; 488 } 489 490 // head 491 /++ 492 Head position in the internal buffer. 493 +/ 494 size_t head; 495 496 // tail 497 /++ 498 Tail position in the internal buffer. 499 +/ 500 size_t tail; 501 502 // caughtUp 503 /++ 504 Whether or not [head] and [tail] point to the same position in the 505 context of a circular array. 506 +/ 507 bool caughtUp; 508 509 // initialised 510 /++ 511 Whether or not at least one element has been added. 512 +/ 513 bool initialised; 514 515 public: 516 // front 517 /++ 518 Returns the front element. 519 520 Returns: 521 An item T. 522 +/ 523 ref auto front() inout 524 in ((buf.length > 0), "Tried to get `front` from a zero-sized " ~ typeof(this).stringof) 525 { 526 return buf[head]; 527 } 528 529 // put 530 /++ 531 Append an item to the buffer. 532 533 If it would be put beyond the end of the buffer, it will wrap around and 534 truncate old values. 535 536 Params: 537 item = Item to add. 538 +/ 539 void put(T item) pure @safe @nogc nothrow 540 in ((buf.length > 0), "Tried to `put` something into a zero-sized " ~ typeof(this).stringof) 541 { 542 if (initialised) ++head %= buf.length; 543 buf[head] = item; 544 tail = head; 545 caughtUp = true; 546 initialised = true; 547 } 548 549 // popFront 550 /++ 551 Advances the current position to the next item in the buffer. 552 +/ 553 void popFront() pure @safe @nogc nothrow 554 in ((buf.length > 0), "Tried to `popFront` a zero-sized " ~ typeof(this).stringof) 555 in (!empty, "Tried to `popFront` an empty " ~ typeof(this).stringof) 556 { 557 if (head == 0) 558 { 559 head = (buf.length + (-1)); 560 caughtUp = false; 561 } 562 else 563 { 564 --head; 565 } 566 } 567 568 static if (dynamic) 569 { 570 // resize 571 /++ 572 Resizes the internal buffer to a specified size. 573 574 Params: 575 size = New size. 576 +/ 577 void resize(const size_t size) pure @safe nothrow 578 { 579 buf.length = size; 580 if (head >= buf.length) head = buf.length +(-1); 581 if (tail >= buf.length) tail = buf.length +(-1); 582 } 583 } 584 585 // opOpAssign 586 /++ 587 Implements `buf ~= someT` (appending) by wrapping `put`. 588 589 Params: 590 op = Operation type, here specialised to "`~`". 591 more = Item to add. 592 +/ 593 void opOpAssign(string op : "~")(const T more) pure @safe @nogc nothrow 594 { 595 return put(more); 596 } 597 598 // size 599 /++ 600 Returns the size of the internal buffer. 601 602 Returns: 603 Internal buffer size. 604 +/ 605 auto size() const inout 606 { 607 return buf.length; 608 } 609 610 // empty 611 /++ 612 Returns whether or not the container is considered empty. 613 614 Mind that the buffer may well still contain old contents. Use `clear` 615 to zero it out. 616 617 Returns: 618 `true` if there are items available to get via `front`, 619 `false` if not. 620 +/ 621 auto empty() const inout 622 { 623 return !caughtUp && (head == tail); 624 } 625 626 // save 627 /++ 628 Implements Range `save`. 629 630 Returns: 631 A shallow copy of the container. 632 +/ 633 auto save() 634 { 635 return this; 636 } 637 638 // dup 639 /++ 640 Makes a deep(er) duplicate of the container. 641 642 Returns: 643 A copy of the current container with the internal buffer explicitly `.dup`ed. 644 +/ 645 auto dup() 646 { 647 auto copy = this; 648 649 static if (dynamic) 650 { 651 copy.buf = this.buf.dup; 652 } 653 654 return copy; 655 } 656 657 // clear 658 /++ 659 Resets the buffer pointers but doesn't clear the contents. 660 +/ 661 void reset() pure @safe @nogc nothrow 662 { 663 head = 0; 664 tail = 0; 665 } 666 667 // clear 668 /++ 669 Zeroes out the buffer's elements, getting rid of old contents. 670 +/ 671 void clear() pure @safe @nogc nothrow 672 { 673 reset(); 674 buf[] = T.init; 675 } 676 } 677 678 /// 679 unittest 680 { 681 import std.conv : text; 682 683 { 684 CircularBuffer!(int, Yes.dynamic) buf; 685 buf.resize(3); 686 687 buf.put(1); 688 assert((buf.front == 1), buf.front.text); 689 buf.put(2); 690 assert((buf.front == 2), buf.front.text); 691 buf.put(3); 692 assert((buf.front == 3), buf.front.text); 693 buf ~= 4; 694 assert((buf.front == 4), buf.front.text); 695 assert((buf.buf[] == [ 4, 2, 3 ]), buf.buf.text); 696 buf ~= 5; 697 assert((buf.front == 5), buf.front.text); 698 buf ~= 6; 699 assert((buf.front == 6), buf.front.text); 700 assert((buf.buf[] == [ 4, 5, 6 ]), buf.buf.text); 701 buf.popFront(); 702 buf.popFront(); 703 buf.popFront(); 704 assert(buf.empty); 705 } 706 { 707 CircularBuffer!(int, No.dynamic, 3) buf; 708 //buf.resize(3); 709 710 buf.put(1); 711 assert((buf.front == 1), buf.front.text); 712 buf.put(2); 713 assert((buf.front == 2), buf.front.text); 714 buf.put(3); 715 assert((buf.front == 3), buf.front.text); 716 buf ~= 4; 717 assert((buf.front == 4), buf.front.text); 718 assert((buf.buf[] == [ 4, 2, 3 ]), buf.buf.text); 719 buf.popFront(); 720 buf.popFront(); 721 buf.popFront(); 722 assert(buf.empty); 723 } 724 { 725 CircularBuffer!(int, No.dynamic, 2) buf; 726 //buf.resize(2); 727 728 buf.put(1); 729 assert((buf.front == 1), buf.front.text); 730 buf.put(2); 731 assert((buf.front == 2), buf.front.text); 732 buf.put(3); 733 assert((buf.front == 3), buf.front.text); 734 buf ~= 4; 735 assert((buf.front == 4), buf.front.text); 736 assert((buf.buf[] == [ 3, 4 ]), buf.buf.text); 737 buf.popFront(); 738 buf.popFront(); 739 assert(buf.empty); 740 //buf.popFront(); // AssertError 741 } 742 { 743 CircularBuffer!(int, No.dynamic, 2) buf; 744 //buf.resize(2); 745 746 buf.put(1); 747 assert((buf.front == 1), buf.front.text); 748 buf.put(2); 749 assert((buf.front == 2), buf.front.text); 750 buf.put(3); 751 assert((buf.front == 3), buf.front.text); 752 buf ~= 4; 753 assert((buf.front == 4), buf.front.text); 754 assert((buf.buf[] == [ 3, 4 ]), buf.buf.text); 755 auto savedBuf = buf.save(); 756 buf.popFront(); 757 buf.popFront(); 758 assert(buf.empty); 759 assert((savedBuf.front == 4), savedBuf.front.text); 760 savedBuf.popFront(); 761 auto savedBuf2 = savedBuf.save(); 762 savedBuf.popFront(); 763 assert(savedBuf.empty); 764 assert((savedBuf2.front == 3), savedBuf2.front.text); 765 savedBuf2.popFront(); 766 assert(savedBuf2.empty); 767 } 768 } 769 770 771 // RehashingAA 772 /++ 773 A wrapper around a native associative array that you can controllably set to 774 automatically rehash as entries are added. 775 776 Params: 777 AA = Associative array type. 778 V = Value type. 779 K = Key type. 780 +/ 781 struct RehashingAA(AA : V[K], V, K) 782 { 783 private: 784 import std.range.primitives : ElementEncodingType; 785 import std.traits : isIntegral; 786 787 /++ 788 Internal associative array. 789 +/ 790 AA aa; 791 792 /++ 793 The number of times this instance has rehashed itself. Private value. 794 +/ 795 uint _numRehashes; 796 797 /++ 798 The number of new entries that has been added since the last rehash. Private value. 799 +/ 800 uint _newKeysSinceLastRehash; 801 802 /++ 803 The number of keys (and length of the array) when the last rehash took place. 804 Private value. 805 +/ 806 size_t _lengthAtLastRehash; 807 808 public: 809 /++ 810 The minimum number of additions needed before the first rehash takes place. 811 +/ 812 uint minimumNeededForRehash = 64; 813 814 /++ 815 The modifier by how much more entries must be added before another rehash 816 takes place, with regards to the current [RehashingAA.aa|aa] length. 817 818 A multiplier of `2.0` means the associative array will be rehashed as 819 soon as its length doubles in size. Must be more than 1. 820 +/ 821 double rehashThresholdMultiplier = 1.5; 822 823 // opIndexAssign 824 /++ 825 Assigns a value into the internal associative array. If it created a new 826 entry, then call [maybeRehash] to bump the internal counter and maybe rehash. 827 828 Example: 829 --- 830 RehashingAA!(int[string]) aa; 831 aa["abc"] = 123; 832 aa["def"] = 456; 833 --- 834 835 Params: 836 value = Value. 837 key = Key. 838 +/ 839 void opIndexAssign(V value, K key) 840 { 841 if (auto existing = key in aa) 842 { 843 *existing = value; 844 } 845 else 846 { 847 aa[key] = value; 848 maybeRehash(); 849 } 850 } 851 852 // opIndex 853 /++ 854 Returns the value for the passed key in the internal associative array. 855 856 Example: 857 --- 858 RehashingAA!(int[string]) aa; 859 aa["abc"] = 123; 860 writeln(aa["abc"]); // 123 861 --- 862 863 Params: 864 key = Key. 865 866 Returns: 867 The value for the key `key`. 868 +/ 869 ref auto opIndex(K key) 870 { 871 return aa[key]; 872 } 873 874 // opIndexUnary 875 /++ 876 Performs a unary operation on a value in the internal associative array. 877 878 Example: 879 --- 880 RehashingAA!(int[string]) aa; 881 aa["abc"] = 123; 882 writeln(-aa["abc"]); // -123 883 --- 884 885 Params: 886 op = Unary operation as a string. 887 key = Key. 888 889 Returns: 890 The result of the operation. 891 +/ 892 ref auto opIndexUnary(string op)(K key) 893 { 894 mixin("return " ~ op ~ "aa[key];"); 895 } 896 897 // opAssign 898 /++ 899 Inherit a native associative array into [RehashingAA.aa|aa]. 900 901 Example: 902 --- 903 RehashingAA!(int[string]) aa; 904 int[string] nativeAA; 905 906 nativeAA["abc"] = 123; 907 aa = nativeAA; 908 assert(aa["abc"] == 123); 909 --- 910 911 Params: 912 aa = Other associative array. 913 +/ 914 void opAssign(V[K] aa) 915 { 916 this.aa = aa; 917 this.rehash(); 918 _numRehashes = 0; 919 } 920 921 // opIndexOpAssign 922 /++ 923 Performs an assingment operation on a value in the internal associative array. 924 925 Example: 926 --- 927 RehashingAA!(int[int]) aa; 928 aa[1] = 42; 929 aa[1] += 1; 930 assert(aa[1] == 43); 931 932 aa[1] *= 2; 933 assert(aa[1] == 86); 934 --- 935 936 Params: 937 op = Assignment operation as a string. 938 value = Value to assign. 939 key = Key. 940 +/ 941 void opIndexOpAssign(string op, U)(U value, K key) 942 if (is(U == V) || is(U == ElementEncodingType!V)) 943 { 944 mixin("aa[key] " ~ op ~ "= value;"); 945 maybeRehash(); 946 } 947 948 // opCast 949 /++ 950 Allows for casting this into the base associative array type. 951 952 Example: 953 --- 954 RehashingAA!(int[string]) aa; 955 aa["abc"] = 123; 956 auto native = cast(int[string])aa; 957 assert(native["abc"] == 123); 958 --- 959 960 Params: 961 T = Type to cast to, here the same as the type of [RehashingAA.aa|aa]. 962 963 Returns: 964 The internal associative array. 965 +/ 966 ref auto opCast(T : AA)() inout 967 { 968 return aa; 969 } 970 971 // aaOf 972 /++ 973 Returns the internal associative array, for when the wrapper is insufficient. 974 975 Example: 976 --- 977 RehashingAA!(int[string]) aa; 978 static assert(is(typeof(aa.aaOf) == int[string])); 979 --- 980 981 Returns: 982 The internal associative array. 983 +/ 984 ref auto aaOf() inout 985 { 986 return aa; 987 } 988 989 // remove 990 /++ 991 Removes a key from the [RehashingAA.aa|aa] associative array by merely 992 invoking `.remove`. 993 994 Example: 995 --- 996 RehashingAA!(int[string]) aa; 997 aa["abc"] = 123; 998 assert("abc" in aa); 999 1000 aa.remove("abc"); 1001 assert("abc" !in aa); 1002 --- 1003 1004 Params: 1005 key = The key to remove. 1006 1007 Returns: 1008 Whatever `aa.remove(key)` returns. 1009 +/ 1010 auto remove(K key) 1011 { 1012 //scope(exit) maybeRehash(); 1013 return aa.remove(key); 1014 } 1015 1016 // maybeRehash 1017 /++ 1018 Bumps the internal counter of new keys since the last rehash, and depending 1019 on the resulting value of it, maybe rehashes. 1020 1021 Returns: 1022 `true` if the associative array was rehashed; `false` if not. 1023 +/ 1024 auto maybeRehash() 1025 { 1026 if (++_newKeysSinceLastRehash > minimumNeededForRehash) 1027 { 1028 if (aa.length > (_lengthAtLastRehash * rehashThresholdMultiplier)) 1029 { 1030 this.rehash(); 1031 return true; 1032 } 1033 } 1034 1035 return false; 1036 } 1037 1038 // clear 1039 /++ 1040 Clears the internal associative array and all counters. 1041 +/ 1042 void clear() 1043 { 1044 aa.clear(); 1045 _newKeysSinceLastRehash = 0; 1046 _lengthAtLastRehash = 0; 1047 _numRehashes = 0; 1048 } 1049 1050 // rehash 1051 /++ 1052 Rehashes the internal associative array, bumping the rehash counter and 1053 zeroing the keys-added counter. Additionally invokes the [onRehashDg] delegate. 1054 1055 Returns: 1056 A reference to the rehashed internal array. 1057 +/ 1058 ref auto rehash() @system 1059 { 1060 scope(exit) if (onRehashDg) onRehashDg(aa); 1061 _lengthAtLastRehash = aa.length; 1062 _newKeysSinceLastRehash = 0; 1063 ++_numRehashes; 1064 aa.rehash(); 1065 return this; 1066 } 1067 1068 // numRehashes 1069 /++ 1070 The number of times this instance has rehashed itself. Accessor. 1071 1072 Returns: 1073 The number of times this instance has rehashed itself. 1074 +/ 1075 auto numRehashes() inout 1076 { 1077 return _numRehashes; 1078 } 1079 1080 // numKeysAddedSinceLastRehash 1081 /++ 1082 The number of new entries that has been added since the last rehash. Accessor. 1083 1084 Returns: 1085 The number of new entries that has been added since the last rehash. 1086 +/ 1087 auto newKeysSinceLastRehash() inout 1088 { 1089 return _newKeysSinceLastRehash; 1090 } 1091 1092 // opBinaryRight 1093 /++ 1094 Wraps `key in aa` to the internal associative array. 1095 1096 Example: 1097 --- 1098 RehashingAA!(int[string]) aa; 1099 aa["abc"] = 123; 1100 assert("abc" in aa); 1101 --- 1102 1103 Params: 1104 op = Operation, here "in". 1105 key = Key. 1106 1107 Returns: 1108 A pointer to the value of the key passed, or `null` if it isn't in 1109 the associative array 1110 +/ 1111 auto opBinaryRight(string op : "in")(K key) inout 1112 { 1113 return key in aa; 1114 } 1115 1116 // byValue 1117 /++ 1118 Wraps the internal associative array's `byValue` function. 1119 1120 Example: 1121 --- 1122 RehashingAA!(int[string]) aa; 1123 aa["abc"] = 123; 1124 aa["def"] = 456; 1125 aa["ghi"] = 789; 1126 1127 foreach (value; aa.byValue) 1128 { 1129 writeln(value); 1130 } 1131 --- 1132 1133 Returns: 1134 The Voldemort returned from the associative array's `byValue` function. 1135 +/ 1136 auto byValue() inout 1137 { 1138 return aa.byValue(); 1139 } 1140 1141 // byKey 1142 /++ 1143 Wraps the internal associative array's `byKey` function. 1144 1145 Example: 1146 --- 1147 RehashingAA!(int[string]) aa; 1148 aa["abc"] = 123; 1149 aa["def"] = 456; 1150 aa["ghi"] = 789; 1151 1152 foreach (key; aa.byKey) 1153 { 1154 writeln(key); 1155 } 1156 --- 1157 1158 Returns: 1159 The Voldemort returned from the associative array's `byKey` function. 1160 +/ 1161 auto byKey() inout 1162 { 1163 return aa.byKey(); 1164 } 1165 1166 // values 1167 /++ 1168 Wraps the internal associative array's `values` function. 1169 1170 Example: 1171 --- 1172 RehashingAA!(int[string]) aa; 1173 aa["abc"] = 123; 1174 aa["def"] = 456; 1175 aa["ghi"] = 789; 1176 1177 auto values = aa.values; // allocate it once 1178 1179 // Order cannot be relied upon 1180 foreach (val; [ 123, 456, 789 ]) 1181 { 1182 import std.algorithm.searching : canFind; 1183 assert(values.canFind(val)); 1184 } 1185 --- 1186 1187 Returns: 1188 A new dynamic array of all values, as returned by the associative array's 1189 `values` function. 1190 +/ 1191 auto values() const 1192 { 1193 return aa.values; 1194 } 1195 1196 // keys 1197 /++ 1198 Wraps the internal associative array's `keys` function. 1199 1200 Example: 1201 --- 1202 RehashingAA!(int[string]) aa; 1203 aa["abc"] = 123; 1204 aa["def"] = 456; 1205 aa["ghi"] = 789; 1206 1207 auto keys = aa.keys; // allocate it once 1208 1209 // Order cannot be relied upon 1210 foreach (key; [ "abc", "def", "ghi" ]) 1211 { 1212 assert(key in aa); 1213 } 1214 --- 1215 1216 Returns: 1217 A new dynamic array of all keys, as returned by the associative array's 1218 `keys` function. 1219 +/ 1220 auto keys() const 1221 { 1222 return aa.keys; 1223 } 1224 1225 // byKeyValue 1226 /++ 1227 Wraps the internal associative array's `byKeyValue` function. 1228 1229 Example: 1230 --- 1231 RehashingAA!(int[string]) aa; 1232 aa["abc"] = 123; 1233 aa["def"] = 456; 1234 aa["ghi"] = 789; 1235 1236 foreach (key, value; aa.byKeyValue) 1237 { 1238 writeln(key, " = ", value); 1239 } 1240 --- 1241 1242 Returns: 1243 A new range of all key-value pairs, as returned by the associative 1244 array's `byKeyValue` function. 1245 +/ 1246 auto byKeyValue() inout 1247 { 1248 return aa.byKeyValue(); 1249 } 1250 1251 // length 1252 /++ 1253 Returns the length of the internal associative array. 1254 1255 Returns: 1256 The length of the internal associative array. 1257 +/ 1258 auto length() const inout 1259 { 1260 return aa.length; 1261 } 1262 1263 // dup 1264 /++ 1265 Duplicates this. Explicitly copies the internal associative array. 1266 1267 If `copyState: false` is passed, it will not copy over the internal state 1268 such as the number of rehashes and keys added since the last rehash. 1269 1270 Example: 1271 --- 1272 RehashingAA!(int[string]) aa; 1273 aa.minimumNeededForRehash = 2; 1274 1275 aa["abc"] = 123; 1276 aa["def"] = 456; 1277 aa["ghi"] = 789; 1278 assert(aa.numRehashes == 1); 1279 1280 auto aa2 = aa.dup(copyState: false); 1281 assert(aa2 == aa); 1282 assert(aa2.numRehashes == 1); 1283 1284 auto aa3 = aa.dup; //(copyState: false); 1285 assert(aa3 == aa); 1286 assert(aa3.numRehashes == 0); 1287 --- 1288 1289 Params: 1290 copyState = (Optional) Whether or not to copy over the internal state. 1291 1292 Returns: 1293 A duplicate of this object. 1294 +/ 1295 auto dup(const bool copyState = false) 1296 { 1297 auto copy = copyState ? 1298 this : 1299 typeof(this).init; 1300 1301 copy.aa = this.aa.dup; 1302 return copy; 1303 } 1304 1305 // require 1306 /++ 1307 Returns the value for the key `key`, inserting `value` lazily if it is not present. 1308 1309 Example: 1310 --- 1311 RehashingAA!(string[int]) aa; 1312 string hello = aa.require(42, "hello"); 1313 assert(hello == "hello"); 1314 assert(aa[42] == "hello"); 1315 --- 1316 1317 Params: 1318 key = Key. 1319 value = Value to insert if the key is not present. 1320 1321 Returns: 1322 The value for the key `key`, or `value` if it was not present. 1323 +/ 1324 ref auto require(K key, lazy V value) 1325 { 1326 if (auto existing = key in aa) 1327 { 1328 return *existing; 1329 } 1330 else 1331 { 1332 aa[key] = value; 1333 return value; 1334 } 1335 } 1336 1337 // get 1338 /++ 1339 Retrieves the value for the key `key`, or returns the default `value` 1340 if there was none. 1341 1342 Example: 1343 --- 1344 RehashingAA!(int[int]) aa; 1345 aa[1] = 42; 1346 aa[2] = 99; 1347 1348 assert(aa.get(1, 0) == 42); 1349 assert(aa.get(2, 0) == 99); 1350 assert(aa.get(0, 0) == 0); 1351 assert(aa.get(3, 999) == 999); 1352 1353 assert(0 !in aa); 1354 assert(3 !in aa); 1355 --- 1356 +/ 1357 ref auto get(K key, lazy V value) 1358 { 1359 if (auto existing = key in aa) 1360 { 1361 return *existing; 1362 } 1363 else 1364 { 1365 return value; 1366 } 1367 } 1368 1369 static if (isIntegral!K) 1370 { 1371 /++ 1372 Reserves a unique key in the associative array. 1373 1374 Note: The key type must be an integral type. 1375 1376 Example: 1377 --- 1378 RehashingAA!(string[int]) aa; 1379 1380 int i = aa.uniqueKey; 1381 assert(i > 0); 1382 assert(i in aa); 1383 assert(aa[i] == string.init); 1384 --- 1385 1386 Params: 1387 min = Optional minimum key value; defaults to `1``. 1388 max = Optional maximum key value; defaults to `K.max`, where `K` is 1389 the key type of the passed associative array. 1390 value = Optional value to assign to the key; defaults to `V.init`, 1391 where `V` is the value type of the passed associative array. 1392 1393 Returns: 1394 A unique key for the passed associative array, for which there is now 1395 a value of `value`.` 1396 1397 See_Also: 1398 [lu.array.uniqueKey] 1399 +/ 1400 auto uniqueKey() 1401 (K min = 1, 1402 K max = K.max, 1403 V value = V.init) 1404 { 1405 static import lu.array; 1406 return lu.array.uniqueKey(aa, min, max, value); 1407 } 1408 } 1409 1410 // update 1411 /++ 1412 Updates the value for the key `key` in the internal associative array, 1413 invoking the first of the passed delegate to insert a new value if it 1414 doesn't exist, or the second selegate to modify it in place if it does. 1415 1416 Note: Doesn't compile with compilers earlier than version 2.088. 1417 1418 Example: 1419 --- 1420 RehashingAA!(int[int]) aa; 1421 1422 assert(1 !in aa); 1423 1424 aa.update(1, 1425 () => 42, 1426 (int i) => i + 1); 1427 assert(aa[1] == 42); 1428 1429 aa.update(1, 1430 () => 42, 1431 (int i) => i + 1); 1432 assert(aa[1] == 43); 1433 --- 1434 1435 Params: 1436 key = Key. 1437 createDg = Delegate to invoke to create a new value if it doesn't exist. 1438 updateDg = Delegate to invoke to update an existing value. 1439 +/ 1440 static if (__VERSION__ >= 2088L) 1441 void update(U) 1442 (K key, 1443 scope V delegate() createDg, 1444 scope U delegate(K) updateDg) 1445 if (is(U == V) || is(U == void)) 1446 { 1447 .object.update(aa, key, createDg, updateDg); 1448 } 1449 1450 // opEquals 1451 /++ 1452 Implements `opEquals` for this type, comparing the internal associative 1453 array with that of another `RehashingAA`. 1454 1455 Example: 1456 --- 1457 RehashingAA!(string[int]) aa1; 1458 aa1[1] = "one"; 1459 1460 RehashingAA!(string[int]) aa2; 1461 aa2[1] = "one"; 1462 assert(aa1 == aa2); 1463 1464 aa2[2] = "two"; 1465 assert(aa1 != aa2); 1466 1467 aa1[2] = "two"; 1468 assert(aa1 == aa2); 1469 --- 1470 1471 Params: 1472 other = Other `RehashingAA` whose internal associative array to compare 1473 with the one of this instance. 1474 1475 Returns: 1476 `true` if the internal associative arrays are equal; `false` if not. 1477 +/ 1478 auto opEquals(typeof(this) other) 1479 { 1480 return (aa == other.aa); 1481 } 1482 1483 // opEquals 1484 /++ 1485 Implements `opEquals` for this type, comparing the internal associative 1486 array with a different one. 1487 1488 Example: 1489 --- 1490 RehashingAA!(string[int]) aa1; 1491 aa1[1] = "one"; 1492 aa1[2] = "two"; 1493 1494 string[int] aa2; 1495 aa2[1] = "one"; 1496 1497 assert(aa1 != aa2); 1498 1499 aa2[2] = "two"; 1500 assert(aa1 == aa2); 1501 --- 1502 1503 Params: 1504 other = Other associative array to compare the internal one with. 1505 1506 Returns: 1507 `true` if the internal associative arrays are equal; `false` if not. 1508 +/ 1509 auto opEquals(AA other) 1510 { 1511 return (aa == other); 1512 } 1513 1514 // this 1515 /++ 1516 Constructor. 1517 1518 Params: 1519 aa = Associative arary to inherit. Taken by reference for now. 1520 +/ 1521 this(AA aa) pure @safe nothrow @nogc 1522 { 1523 this.aa = aa; 1524 } 1525 1526 // onRehashDg 1527 /++ 1528 Delegate called when rehashing takes place. 1529 1530 Example: 1531 --- 1532 uint counter; 1533 1534 void dg(ref int[string] aa) 1535 { 1536 ++counter; 1537 writeln("Rehashed!"); 1538 } 1539 1540 RehashingAA!(int[string]) aa; 1541 aa.onRehashDg = &dg; 1542 aa.minimumNeededForRehash = 2; 1543 1544 aa["abc"] = 123; 1545 aa["def"] = 456; 1546 aa["ghi"] = 789; 1547 1548 assert(aa.numRehashes == 1); 1549 assert(counter == 1); 1550 --- 1551 +/ 1552 void delegate(ref AA) @system onRehashDg; 1553 } 1554 1555 /// 1556 unittest 1557 { 1558 import std.conv : to; 1559 1560 { 1561 uint counter; 1562 1563 void dg(ref int[string] aa) 1564 { 1565 ++counter; 1566 } 1567 1568 RehashingAA!(int[string]) aa; 1569 aa.onRehashDg = &dg; 1570 aa.minimumNeededForRehash = 2; 1571 1572 aa["abc"] = 123; 1573 aa["def"] = 456; 1574 assert((aa.newKeysSinceLastRehash == 2), aa.newKeysSinceLastRehash.to!string); 1575 assert((aa.numRehashes == 0), aa.numRehashes.to!string); 1576 aa["ghi"] = 789; 1577 assert((aa.numRehashes == 1), aa.numRehashes.to!string); 1578 assert((aa.newKeysSinceLastRehash == 0), aa.newKeysSinceLastRehash.to!string); 1579 aa.rehash(); 1580 assert((aa.numRehashes == 2), aa.numRehashes.to!string); 1581 assert((counter == 2), counter.to!string); 1582 1583 auto realAA = cast(int[string])aa; 1584 assert("abc" in realAA); 1585 assert("def" in realAA); 1586 1587 auto alsoRealAA = aa.aaOf; 1588 assert("ghi" in alsoRealAA); 1589 assert("jkl" !in alsoRealAA); 1590 1591 auto aa2 = aa.dup(copyState: true); 1592 assert((aa2.numRehashes == 2), aa2.numRehashes.to!string); 1593 aa2["jkl"] = 123; 1594 assert("jkl" in aa2); 1595 assert("jkl" !in aa); 1596 1597 auto aa3 = aa.dup(); //(copyState: false); 1598 assert(!aa3.numRehashes, aa3.numRehashes.to!string); 1599 assert(aa3.aaOf == aa.aaOf); 1600 assert(aa3.aaOf !is aa.aaOf); 1601 } 1602 { 1603 RehashingAA!(int[int]) aa; 1604 aa[1] = 2; 1605 ++aa[1]; 1606 assert((aa[1] == 3), aa[1].to!string); 1607 assert((-aa[1] == -3), (-aa[1]).to!string); 1608 } 1609 { 1610 RehashingAA!(int[int]) aa; 1611 aa[1] = 42; 1612 aa[1] += 1; 1613 assert(aa[1] == 43); 1614 1615 aa[1] *= 2; 1616 assert(aa[1] == 86); 1617 } 1618 { 1619 RehashingAA!(int[string]) aa; 1620 static assert(is(typeof(aa.aaOf()) == int[string])); 1621 1622 aa["abc"] = 123; 1623 auto native = cast(int[string])aa; 1624 assert(native["abc"] == 123); 1625 } 1626 { 1627 RehashingAA!(int[string]) aa; 1628 aa["abc"] = 123; 1629 aa["def"] = 456; 1630 assert((aa.length == 2), aa.length.to!string); 1631 aa.remove("abc"); 1632 assert((aa.length == 1), aa.length.to!string); 1633 aa.remove("def"); 1634 assert(!aa.length, aa.length.to!string); 1635 } 1636 { 1637 RehashingAA!(int[string]) aa; 1638 aa["abc"] = 123; 1639 aa["def"] = 456; 1640 aa["ghi"] = 789; 1641 1642 foreach (value; aa.byValue) 1643 { 1644 import std.algorithm.comparison : among; 1645 assert(value.among!(123, 456, 789), value.to!string); 1646 } 1647 } 1648 { 1649 RehashingAA!(int[string]) aa; 1650 aa["abc"] = 123; 1651 aa["def"] = 456; 1652 aa["ghi"] = 789; 1653 1654 foreach (key; aa.byKey) 1655 { 1656 assert(key in aa); 1657 } 1658 } 1659 { 1660 RehashingAA!(int[string]) aa; 1661 aa["abc"] = 123; 1662 aa["def"] = 456; 1663 aa["ghi"] = 789; 1664 1665 auto values = aa.values; // allocate it once 1666 1667 // Order cannot be relied upon 1668 foreach (val; [ 123, 456, 789 ]) 1669 { 1670 import std.algorithm.searching : canFind; 1671 assert(values.canFind(val)); 1672 } 1673 } 1674 { 1675 RehashingAA!(int[string]) aa; 1676 aa["abc"] = 123; 1677 aa["def"] = 456; 1678 aa["ghi"] = 789; 1679 1680 auto keys = aa.keys; // allocate it once 1681 1682 // Order cannot be relied upon 1683 foreach (key; [ "abc", "def", "ghi" ]) 1684 { 1685 assert(key in aa); 1686 } 1687 } 1688 { 1689 RehashingAA!(int[string]) aa; 1690 aa["abc"] = 123; 1691 aa["def"] = 456; 1692 aa["ghi"] = 789; 1693 1694 foreach (kv; aa.byKeyValue) 1695 { 1696 assert(kv.key in aa); 1697 assert(aa[kv.key] == kv.value); 1698 } 1699 } 1700 { 1701 RehashingAA!(string[int]) aa; 1702 string hello = aa.require(42, "hello"); 1703 assert(hello == "hello"); 1704 assert(aa[42] == "hello"); 1705 } 1706 { 1707 RehashingAA!(int[int]) aa; 1708 aa[1] = 42; 1709 aa[2] = 99; 1710 1711 assert(aa.get(1, 0) == 42); 1712 assert(aa.get(2, 0) == 99); 1713 assert(aa.get(0, 0) == 0); 1714 assert(aa.get(3, 999) == 999); 1715 1716 assert(0 !in aa); 1717 assert(3 !in aa); 1718 } 1719 static if (__VERSION__ >= 2088L) 1720 {{ 1721 RehashingAA!(int[int]) aa; 1722 1723 assert(1 !in aa); 1724 1725 aa.update(1, 1726 () => 42, 1727 (int i) => i + 1); 1728 assert(aa[1] == 42); 1729 1730 aa.update(1, 1731 () => 42, 1732 (int i) => i + 1); 1733 assert(aa[1] == 43); 1734 }} 1735 { 1736 RehashingAA!(string[int]) aa1; 1737 aa1[1] = "one"; 1738 1739 RehashingAA!(string[int]) aa2; 1740 aa2[1] = "one"; 1741 assert(aa1 == aa2); 1742 1743 aa2[2] = "two"; 1744 assert(aa1 != aa2); 1745 1746 aa1[2] = "two"; 1747 assert(aa1 == aa2); 1748 } 1749 { 1750 RehashingAA!(string[int]) aa1; 1751 aa1[1] = "one"; 1752 aa1[2] = "two"; 1753 1754 string[int] aa2; 1755 aa2[1] = "one"; 1756 1757 assert(aa1 != aa2); 1758 1759 aa2[2] = "two"; 1760 assert(aa1 == aa2); 1761 } 1762 { 1763 RehashingAA!(string[int]) aa; 1764 int i = aa.uniqueKey; 1765 assert(i > 0); 1766 assert(i in aa); 1767 assert(aa[i] == string.init); 1768 } 1769 } 1770 1771 1772 // MutexedAA 1773 /++ 1774 An associative array and a [core.sync.mutex.Mutex|Mutex]. Wraps associative 1775 array operations in mutex locks. 1776 1777 Example: 1778 --- 1779 MutexedAA!(string[int]) aa; 1780 aa.setup(); // important! 1781 1782 aa[1] = "one"; 1783 aa[2] = "two"; 1784 aa[3] = "three"; 1785 1786 auto hasOne = aa.has(1); 1787 assert(hasOne); 1788 assert(aa[1] == "one"); 1789 1790 assert(aa[2] == "two"); 1791 1792 auto three = aa.get(3); 1793 assert(three == "three"); 1794 1795 auto four = aa.get(4, "four"); 1796 assert(four == "four"); 1797 1798 auto five = aa.require(5, "five"); 1799 assert(five == "five"); 1800 assert(aa[5] == "five"); 1801 1802 auto keys = aa.keys; 1803 assert(keys.canFind(1)); 1804 assert(keys.canFind(5)); 1805 assert(!keys.canFind(6)); 1806 1807 auto values = aa.values; 1808 assert(values.canFind("one")); 1809 assert(values.canFind("four")); 1810 assert(!values.canFind("six")); 1811 1812 aa.rehash(); 1813 --- 1814 1815 Params: 1816 AA = Associative array type. 1817 V = Value type. 1818 K = Key type. 1819 +/ 1820 struct MutexedAA(AA : V[K], V, K) 1821 { 1822 private: 1823 import std.range.primitives : ElementEncodingType; 1824 import std.traits : isIntegral; 1825 import core.sync.mutex : Mutex; 1826 1827 /++ 1828 [core.sync.mutex.Mutex|Mutex] to lock the associative array with. 1829 +/ 1830 shared Mutex mutex; 1831 1832 public: 1833 /++ 1834 The internal associative array. 1835 +/ 1836 shared AA aa; 1837 1838 /++ 1839 Sets up this instance. Does nothing if it has already been set up. 1840 1841 Instantiates the [mutex] and minimally initialises the associative array 1842 by assigning and removing a dummy value. 1843 +/ 1844 void setup() nothrow 1845 { 1846 if (mutex) return; 1847 1848 mutex = new shared Mutex; 1849 (cast()mutex).lock_nothrow(); 1850 1851 if (K.init !in cast(AA)aa) 1852 { 1853 (cast(AA)aa)[K.init] = V.init; 1854 (cast(AA)aa).remove(K.init); 1855 } 1856 1857 (cast()mutex).unlock_nothrow(); 1858 } 1859 1860 /++ 1861 Returns whether or not this instance has been set up. 1862 1863 Returns: 1864 Whether or not the [mutex] was instantiated, and thus whether this 1865 instance has been set up. 1866 +/ 1867 auto isReady() inout 1868 { 1869 return (mutex !is null); 1870 } 1871 1872 /++ 1873 `aa[key] = value` array assign operation, wrapped in a mutex lock. 1874 1875 Example: 1876 --- 1877 MutexedAA!(string[int]) aa; 1878 aa.setup(); // important! 1879 1880 aa[1] = "one"; 1881 aa[2] = "two"; 1882 --- 1883 1884 Params: 1885 value = Value. 1886 key = Key. 1887 1888 Returns: 1889 The value assigned. 1890 +/ 1891 auto opIndexAssign(V value, K key) 1892 in (mutex, typeof(this).stringof ~ " has null Mutex") 1893 { 1894 (cast()mutex).lock_nothrow(); 1895 (cast(AA)aa)[key] = value; 1896 (cast()mutex).unlock_nothrow(); 1897 return value; 1898 } 1899 1900 /++ 1901 `aa[key]` array retrieve operation, wrapped in a mutex lock. 1902 1903 Example: 1904 --- 1905 MutexedAA!(string[int]) aa; 1906 aa.setup(); // important! 1907 1908 // ... 1909 1910 string one = aa[1]; 1911 writeln(aa[2]); 1912 --- 1913 1914 Params: 1915 key = Key. 1916 1917 Returns: 1918 The value assigned. 1919 +/ 1920 auto opIndex(K key) 1921 in (mutex, typeof(this).stringof ~ " has null Mutex") 1922 { 1923 (cast()mutex).lock_nothrow(); 1924 auto value = (cast(AA)aa)[key]; 1925 (cast()mutex).unlock_nothrow(); 1926 return value; 1927 } 1928 1929 /++ 1930 Returns whether or not the passed key is in the associative array. 1931 1932 Example: 1933 --- 1934 MutexedAA!(string[int]) aa; 1935 aa.setup(); // important! 1936 1937 aa[1] = "one"; 1938 assert(aa.has(1)); 1939 --- 1940 1941 Params: 1942 key = Key. 1943 1944 Returns: 1945 `true` if the key is in the associative array; `false` if not. 1946 +/ 1947 auto has(K key) 1948 in (mutex, typeof(this).stringof ~ " has null Mutex") 1949 { 1950 (cast()mutex).lock_nothrow(); 1951 auto exists = (key in cast(AA)aa) !is null; 1952 (cast()mutex).unlock_nothrow(); 1953 return exists; 1954 } 1955 1956 /++ 1957 `aa.remove(key)` array operation, wrapped in a mutex lock. 1958 1959 Example: 1960 --- 1961 MutexedAA!(string[int]) aa; 1962 aa.setup(); // important! 1963 1964 aa[1] = "one"; 1965 assert(aa.has(1)); 1966 1967 aa.remove(1); 1968 assert(!aa.has(1)); 1969 --- 1970 1971 Params: 1972 key = Key. 1973 1974 Returns: 1975 Whatever `aa.remove(key)` returns. 1976 +/ 1977 auto remove(K key) 1978 in (mutex, typeof(this).stringof ~ " has null Mutex") 1979 { 1980 (cast()mutex).lock_nothrow(); 1981 auto value = (cast(AA)aa).remove(key); 1982 (cast()mutex).unlock_nothrow(); 1983 return value; 1984 } 1985 1986 static if (isIntegral!K) 1987 { 1988 /++ 1989 Reserves a unique key in the associative array. 1990 1991 Note: The key type must be an integral type. 1992 1993 Example: 1994 --- 1995 MutexedAA!(string[int]) aa; 1996 aa.setup(); // important! 1997 1998 int i = aa.uniqueKey; 1999 assert(i > 0); 2000 assert(aa.has(i)); 2001 assert(aa[i] == string.init); 2002 --- 2003 2004 Params: 2005 min = Optional minimum key value; defaults to `1``. 2006 max = Optional maximum key value; defaults to `K.max`, where `K` is 2007 the key type of the passed associative array. 2008 value = Optional value to assign to the key; defaults to `V.init`, 2009 where `V` is the value type of the passed associative array. 2010 2011 Returns: 2012 A unique key for the passed associative array, for which there is now 2013 a value of `value`.` 2014 2015 See_Also: 2016 [lu.array.uniqueKey] 2017 +/ 2018 auto uniqueKey() 2019 (K min = 1, 2020 K max = K.max, 2021 V value = V.init) 2022 in (mutex, typeof(this).stringof ~ " has null Mutex") 2023 { 2024 static import lu.array; 2025 2026 (cast()mutex).lock_nothrow(); 2027 auto key = lu.array.uniqueKey(*(cast(AA*)&aa), min, max, value); 2028 (cast()mutex).unlock_nothrow(); 2029 return key; 2030 } 2031 } 2032 2033 /++ 2034 Implements `opEquals` for this type, comparing the internal associative 2035 array with that of another `MutexedAA`. 2036 2037 Example: 2038 --- 2039 MutexedAA!(string[int]) aa1; 2040 aa1.setup(); // important! 2041 aa1[1] = "one"; 2042 2043 MutexedAA!(string[int]) aa2; 2044 aa2.setup(); // as above 2045 aa2[1] = "one"; 2046 assert(aa1 == aa2); 2047 2048 aa2[2] = "two"; 2049 assert(aa1 != aa2); 2050 2051 aa1[2] = "two"; 2052 assert(aa1 == aa2); 2053 --- 2054 2055 Params: 2056 other = Other `MutexedAA` whose internal associative array to compare 2057 with the one of this instance. 2058 2059 Returns: 2060 `true` if the internal associative arrays are equal; `false` if not. 2061 +/ 2062 auto opEquals(typeof(this) other) 2063 in (mutex, typeof(this).stringof ~ " has null Mutex") 2064 { 2065 (cast()mutex).lock_nothrow(); 2066 auto isEqual = (cast(AA)aa == cast(AA)(other.aa)); 2067 (cast()mutex).unlock_nothrow(); 2068 return isEqual; 2069 } 2070 2071 /++ 2072 Implements `opEquals` for this type, comparing the internal associative 2073 array with a different one. 2074 2075 Example: 2076 --- 2077 MutexedAA!(string[int]) aa1; 2078 aa1.setup(); // important! 2079 aa1[1] = "one"; 2080 aa1[2] = "two"; 2081 2082 string[int] aa2; 2083 aa2[1] = "one"; 2084 2085 assert(aa1 != aa2); 2086 2087 aa2[2] = "two"; 2088 assert(aa1 == aa2); 2089 --- 2090 2091 Params: 2092 other = Other associative array to compare the internal one with. 2093 2094 Returns: 2095 `true` if the internal associative arrays are equal; `false` if not. 2096 +/ 2097 auto opEquals(AA other) 2098 in (mutex, typeof(this).stringof ~ " has null Mutex") 2099 { 2100 (cast()mutex).lock_nothrow(); 2101 auto isEqual = (cast(AA)aa == other); 2102 (cast()mutex).unlock_nothrow(); 2103 return isEqual; 2104 } 2105 2106 /++ 2107 Rehashes the internal associative array. 2108 2109 Example: 2110 --- 2111 MutexedAA!(string[int]) aa; 2112 aa.setup(); // important! 2113 2114 aa[1] = "one"; 2115 aa[2] = "two"; 2116 aa.rehash(); 2117 --- 2118 2119 Returns: 2120 A reference to the rehashed internal array. 2121 +/ 2122 auto rehash() 2123 in (mutex, typeof(this).stringof ~ " has null Mutex") 2124 { 2125 (cast()mutex).lock_nothrow(); 2126 auto rehashed = (cast(AA)aa).rehash(); 2127 (cast()mutex).unlock_nothrow(); 2128 return rehashed; 2129 } 2130 2131 /++ 2132 Clears the internal associative array. 2133 2134 Example: 2135 --- 2136 MutexedAA!(string[int]) aa; 2137 aa.setup(); // important! 2138 2139 aa[1] = "one"; 2140 aa[2] = "two"; 2141 assert(aa.has(1)); 2142 2143 aa.clear(); 2144 assert(!aa.has(2)); 2145 --- 2146 +/ 2147 void clear() 2148 in (mutex, typeof(this).stringof ~ " has null Mutex") 2149 { 2150 (cast()mutex).lock_nothrow(); 2151 (cast(AA)aa).clear(); 2152 (cast()mutex).unlock_nothrow(); 2153 } 2154 2155 /++ 2156 Returns the length of the internal associative array. 2157 2158 Example: 2159 --- 2160 MutexedAA!(string[int]) aa; 2161 aa.setup(); // important! 2162 2163 assert(aa.length == 0); 2164 aa[1] = "one"; 2165 aa[2] = "two"; 2166 assert(aa.length == 2); 2167 --- 2168 2169 Returns: 2170 The length of the internal associative array. 2171 +/ 2172 auto length() 2173 in (mutex, typeof(this).stringof ~ " has null Mutex") 2174 { 2175 (cast()mutex).lock_nothrow(); 2176 auto length = (cast(AA)aa).length; 2177 (cast()mutex).unlock_nothrow(); 2178 return length; 2179 } 2180 2181 /++ 2182 Returns the value for the key `key`, inserting `value` lazily if it is not present. 2183 2184 Example: 2185 --- 2186 MutexedAA!(string[int]) aa; 2187 aa.setup(); // important! 2188 2189 assert(!aa.has(42)); 2190 string hello = aa.require(42, "hello"); 2191 assert(hello == "hello"); 2192 assert(aa[42] == "hello"); 2193 --- 2194 2195 Params: 2196 key = Key. 2197 value = Lazy value. 2198 2199 Returns: 2200 The value for the key `key`, or `value` if there was no value there. 2201 +/ 2202 auto require(K key, lazy V value) 2203 in (mutex, typeof(this).stringof ~ " has null Mutex") 2204 { 2205 V retval; 2206 2207 (cast()mutex).lock_nothrow(); 2208 if (auto existing = key in cast(AA)aa) 2209 { 2210 retval = *existing; 2211 } 2212 else 2213 { 2214 (cast(AA)aa)[key] = value; 2215 retval = value; 2216 } 2217 2218 (cast()mutex).unlock_nothrow(); 2219 return retval; 2220 } 2221 2222 /++ 2223 Returns a new dynamic array of all the keys in the internal associative array. 2224 2225 Example: 2226 --- 2227 MutexedAA!(int[int]) aa; 2228 aa.setup(); // important! 2229 aa[1] = 42; 2230 aa[2] = 99; 2231 2232 auto keys = aa.keys; 2233 assert(keys.canFind(1)); 2234 assert(keys.canFind(2)); 2235 assert(!keys.canFind(3)); 2236 --- 2237 2238 Returns: 2239 A new `K[]` of all the AA keys. 2240 +/ 2241 auto keys() 2242 in (mutex, typeof(this).stringof ~ " has null Mutex") 2243 { 2244 (cast()mutex).lock_nothrow(); 2245 auto keys = (cast(AA)aa).keys; // allocates a new array 2246 (cast()mutex).unlock_nothrow(); 2247 return keys; 2248 } 2249 2250 /++ 2251 Returns a new dynamic array of all the values in the internal associative array. 2252 2253 Example: 2254 --- 2255 MutexedAA!(int[int]) aa; 2256 aa.setup(); // important! 2257 aa[1] = 42; 2258 aa[2] = 99; 2259 2260 auto values = aa.values; 2261 assert(values.canFind(42)); 2262 assert(values.canFind(99)); 2263 assert(!values.canFind(0)); 2264 --- 2265 2266 Returns: 2267 A new `V[]` of all the AA values. 2268 +/ 2269 auto values() 2270 in (mutex, typeof(this).stringof ~ " has null Mutex") 2271 { 2272 (cast()mutex).lock_nothrow(); 2273 auto values = (cast(AA)aa).values; // as above 2274 (cast()mutex).unlock_nothrow(); 2275 return values; 2276 } 2277 2278 /++ 2279 Retrieves the value for the key `key`, or returns the default `value` 2280 if there was none. 2281 2282 Example: 2283 --- 2284 MutexedAA!(int[int]) aa; 2285 aa.setup(); // important! 2286 aa[1] = 42; 2287 aa[2] = 99; 2288 2289 assert(aa.get(1, 0) == 42); 2290 assert(aa.get(2, 0) == 99); 2291 assert(aa.get(0, 0) == 0); 2292 assert(aa.get(3, 999) == 999); 2293 2294 assert(!aa.has(0)); 2295 assert(!aa.has(3)); 2296 --- 2297 2298 Params: 2299 key = Key. 2300 value = Lazy default value. 2301 2302 Returns: 2303 The value for the key `key`, or `value` if there was no value there. 2304 +/ 2305 auto get(K key, lazy V value) 2306 in (mutex, typeof(this).stringof ~ " has null Mutex") 2307 { 2308 (cast()mutex).lock_nothrow(); 2309 auto existing = key in cast(AA)aa; 2310 auto retval = existing ? *existing : value; 2311 (cast()mutex).unlock_nothrow(); 2312 return retval; 2313 } 2314 2315 /++ 2316 Updates the value for the key `key` in the internal associative array, 2317 invoking the first of the passed delegate to insert a new value if it 2318 doesn't exist, or the second selegate to modify it in place if it does. 2319 2320 Note: Doesn't compile with compilers earlier than version 2.088. 2321 2322 Example: 2323 --- 2324 MutexedAA!(int[int]) aa; 2325 aa.setup(); // important! 2326 2327 assert(!aa.has(1)); 2328 2329 aa.update(1, 2330 () => 42, 2331 (int i) => i + 1); 2332 assert(aa[1] == 42); 2333 2334 aa.update(1, 2335 () => 42, 2336 (int i) => i + 1); 2337 assert(aa[1] == 43); 2338 --- 2339 2340 Params: 2341 key = Key. 2342 createDg = Delegate to invoke to create a new value if it doesn't exist. 2343 updateDg = Delegate to invoke to update an existing value. 2344 +/ 2345 static if (__VERSION__ >= 2088L) 2346 void update(U) 2347 (K key, 2348 scope V delegate() createDg, 2349 scope U delegate(K) updateDg) 2350 if (is(U == V) || is(U == void)) 2351 in (mutex, typeof(this).stringof ~ " has null Mutex") 2352 { 2353 (cast()mutex).lock_nothrow(); 2354 .object.update((*(cast(AA*)&aa)), key, createDg, updateDg); 2355 (cast()mutex).unlock_nothrow(); 2356 } 2357 2358 /++ 2359 Implements unary operations by mixin strings. 2360 2361 Example: 2362 --- 2363 MutexedAA!(int[int]) aa; 2364 aa.setup(); // important! 2365 2366 aa[1] = 42; 2367 assert(-aa[1] == -42); 2368 --- 2369 2370 Params: 2371 op = Operation, here a unary operator. 2372 key = Key. 2373 2374 Returns: 2375 The result of the operation. 2376 +/ 2377 auto opIndexUnary(string op)(K key) 2378 //if (isIntegral!V) 2379 in (mutex, typeof(this).stringof ~ " has null Mutex") 2380 { 2381 (cast()mutex).lock_nothrow(); 2382 mixin("auto value = " ~ op ~ "(cast(AA)aa)[key];"); 2383 (cast()mutex).unlock_nothrow(); 2384 return value; 2385 } 2386 2387 /++ 2388 Implements index assign operations by mixin strings. 2389 2390 Example: 2391 --- 2392 MutexedAA!(int[int]) aa; 2393 aa.setup(); // important! 2394 2395 aa[1] = 42; 2396 aa[1] += 1; 2397 assert(aa[1] == 43); 2398 2399 aa[1] *= 2; 2400 assert(aa[1] == 86); 2401 --- 2402 2403 Params: 2404 op = Operation, here an index assign operator. 2405 value = Value. 2406 key = Key. 2407 +/ 2408 void opIndexOpAssign(string op, U)(U value, K key) 2409 if (is(U == V) || is(U == ElementEncodingType!V)) 2410 in (mutex, typeof(this).stringof ~ " has null Mutex") 2411 { 2412 (cast()mutex).lock_nothrow(); 2413 mixin("(*(cast(AA*)&aa))[key] " ~ op ~ "= value;"); 2414 (cast()mutex).unlock_nothrow(); 2415 } 2416 } 2417 2418 /// 2419 unittest 2420 { 2421 { 2422 MutexedAA!(string[int]) aa1; 2423 assert(!aa1.isReady); 2424 aa1.setup(); 2425 assert(aa1.isReady); 2426 aa1.setup(); // extra setups ignored 2427 2428 MutexedAA!(string[int]) aa2; 2429 aa2.setup(); 2430 2431 aa1[42] = "hello"; 2432 aa2[42] = "world"; 2433 assert(aa1 != aa2); 2434 2435 aa1[42] = "world"; 2436 assert(aa1 == aa2); 2437 2438 aa2[99] = "goodbye"; 2439 assert(aa1 != aa2); 2440 } 2441 { 2442 MutexedAA!(string[int]) aa; 2443 aa.setup(); 2444 2445 assert(!aa.has(42)); 2446 aa.require(42, "hello"); 2447 assert((aa[42] == "hello"), aa[42]); 2448 2449 bool set1; 2450 assert(!aa.has(99)); 2451 string world1 = aa.require(99, { set1 = true; return "world"; }()); 2452 assert(set1); 2453 assert((world1 == "world"), world1); 2454 assert((aa[99] == "world"), aa[99]); 2455 2456 bool set2; 2457 string world2 = aa.require(99, { set2 = true; return "goodbye"; }()); 2458 assert(!set2); 2459 assert((world2 != "goodbye"), world2); 2460 assert((aa[99] != "goodbye"), aa[99]); 2461 } 2462 { 2463 import std.concurrency : Tid, send, spawn; 2464 import std.conv : to; 2465 import core.time : MonoTime, seconds; 2466 2467 static immutable timeout = 1.seconds; 2468 2469 static void workerFn(MutexedAA!(string[int]) aa) 2470 { 2471 static void _assert( 2472 lazy bool condition, 2473 const string message = "unittest failure", 2474 const string file = __FILE__, 2475 const uint line = __LINE__) 2476 { 2477 if (!condition) 2478 { 2479 import std.format : format; 2480 import std.stdio : writeln; 2481 2482 enum pattern = "core.exception.AssertError@%s(%d): %s"; 2483 immutable assertMessage = pattern.format(file, line, message); 2484 writeln(assertMessage); 2485 assert(0, assertMessage); 2486 } 2487 } 2488 2489 _assert(aa.isReady, "MutexedAA passed to worker was not set up properly"); 2490 2491 bool halt; 2492 2493 while (!halt) 2494 { 2495 import std.concurrency : OwnerTerminated, receiveTimeout; 2496 import std.variant : Variant; 2497 2498 immutable receivedSomething = receiveTimeout(timeout, 2499 (bool _) 2500 { 2501 halt = true; 2502 }, 2503 (int i) 2504 { 2505 _assert((aa.length == i-1), "Incorrect MutexedAA length before insert"); 2506 aa[i] = i.to!string; 2507 _assert((aa.length == i), "Incorrect MutexedAA length after insert"); 2508 }, 2509 (OwnerTerminated _) 2510 { 2511 halt = true; 2512 }, 2513 (Variant v) 2514 { 2515 import std.stdio : writeln; 2516 writeln("MutexedAA unit test worker received unknown message: ", v); 2517 halt = true; 2518 } 2519 ); 2520 2521 if (!receivedSomething) return; 2522 } 2523 } 2524 2525 MutexedAA!(string[int]) aa; 2526 aa.setup(); 2527 2528 auto worker = spawn(&workerFn, aa); 2529 immutable start = MonoTime.currTime; 2530 2531 foreach (/*immutable*/ i; 1..10) // start at 1 to enable length checks in worker 2532 { 2533 worker.send(i); 2534 aa.setup(); 2535 auto present = aa.has(i); 2536 2537 while (!present && (MonoTime.currTime - start) < timeout) 2538 { 2539 import core.thread : Thread; 2540 import core.time : msecs; 2541 2542 static immutable briefWait = 2.msecs; 2543 Thread.sleep(briefWait); 2544 present = aa.has(i); 2545 } 2546 2547 assert(present, "MutexedAA unit test worker timed out responding to " ~ i.to!string); 2548 assert((aa[i] == i.to!string), aa[i]); 2549 } 2550 2551 worker.send(true); // halt 2552 } 2553 { 2554 import std.algorithm.searching : canFind; 2555 2556 MutexedAA!(int[int]) aa; 2557 aa.setup(); 2558 2559 aa[1] = 42; 2560 aa[2] = 99; 2561 assert(aa.length == 2); 2562 2563 auto keys = aa.keys; 2564 assert(keys.canFind(1)); 2565 assert(keys.canFind(2)); 2566 assert(!keys.canFind(3)); 2567 2568 auto values = aa.values; 2569 assert(values.canFind(42)); 2570 assert(values.canFind(99)); 2571 assert(!values.canFind(0)); 2572 2573 assert(aa.get(1, 0) == 42); 2574 assert(aa.get(2, 0) == 99); 2575 assert(aa.get(0, 0) == 0); 2576 assert(aa.get(3, 999) == 999); 2577 } 2578 { 2579 MutexedAA!(int[int]) aa1; 2580 aa1.setup(); 2581 2582 aa1[1] = 42; 2583 aa1[2] = 99; 2584 2585 int[int] aa2; 2586 2587 aa2[1] = 42; 2588 assert(aa1 != aa2); 2589 2590 aa2[2] = 99; 2591 assert(aa1 == aa2); 2592 2593 ++aa2[2]; 2594 assert(aa2[2] == 100); 2595 2596 aa2[1] += 1; 2597 assert(aa2[1] == 43); 2598 2599 aa2[1] -= 1; 2600 assert(aa2[1] == 42); 2601 2602 aa2[1] *= 2; 2603 assert(aa2[1] == 84); 2604 2605 int i = -aa2[1]; 2606 assert(i == -84); 2607 } 2608 { 2609 MutexedAA!(char[][int]) aa; 2610 aa.setup(); 2611 2612 aa[1] ~= 'a'; 2613 aa[1] ~= 'b'; 2614 aa[1] ~= 'c'; 2615 assert(aa[1] == "abc".dup); 2616 2617 aa[1] ~= [ 'd', 'e', 'f' ]; 2618 assert(aa[1] == "abcdef".dup); 2619 } 2620 { 2621 MutexedAA!(int[int]) aa; 2622 aa.setup(); 2623 2624 immutable key = aa.uniqueKey; 2625 assert(key > 0); 2626 2627 assert(aa.has(key)); 2628 assert(aa[key] == int.init); 2629 aa.remove(key); 2630 assert(!aa.has(key)); 2631 2632 immutable key2 = aa.uniqueKey(1, 2, -1); 2633 assert(key2 == 1); 2634 assert(aa.has(key2)); 2635 assert(aa[key2] == -1); 2636 } 2637 static if (__VERSION__ >= 2088L) 2638 {{ 2639 MutexedAA!(int[int]) aa; 2640 aa.setup(); 2641 2642 assert(!aa.has(1)); 2643 2644 aa.update(1, 2645 () => 42, 2646 (int i) => i + 1); 2647 assert(aa.has(1)); 2648 assert(aa[1] == 42); 2649 2650 aa.update(1, 2651 () => 42, 2652 (int i) => i + 1); 2653 assert(aa[1] == 43); 2654 }} 2655 }