1 module judy.judyl; 2 3 import core.exception; 4 import core.memory; 5 import std.array; 6 import std.range; 7 import std.traits; 8 9 import judy.libjudy; 10 11 /* 12 Provides D like wrapper around the libjudy C library. Items in the array 13 are indexed by size_t. 14 15 Supports containing the following types: 16 17 - Heap allocated references (classes) 18 - Pointers to heap allocated structs, primitives (no arrays) 19 - Scalar types (these are copied, see std.traits.isScalarType) 20 21 Since libjudy is a C library, management of memory becomes an issue. 22 By default for non scalar types JudyLArray will add stored 23 items to the GC's roots. This ensures that if the only pointer 24 to your items is within the judy array that the items will not 25 be collected. 26 27 If you don't want to use the GC (you're using malloc or your own allocator), 28 then it can be turned off by passing UseGC = false to the template 29 parameters. 30 31 NOTE: Passing in pointers to anything on the stack is very bad 32 and will probably cause nasty things to happen. JudyLArray 33 assumes (other than for scalars which it just copies into itself) 34 that your items are long living and won't be freed 35 out from underneath it. You have been warned. 36 */ 37 38 struct JudyLArray(ElementType, bool UseGC = true) if ( 39 isPointer!ElementType || // ElementType is a pointer 40 is(ElementType : Object) || // ElementType is an object 41 isScalarType!ElementType // ElementType is a scalar 42 ) 43 { 44 public: 45 @disable this(this); 46 47 ~this() 48 { 49 static if (UseGC && hasIndirections!ElementType) 50 { 51 // Iterate over all entries and remove them from the GC 52 // roots 53 foreach(ref entry; this[]) 54 { 55 GC.removeRoot(cast(void*)entry.value); 56 GC.clrAttr(cast(void*)entry.value, GC.BlkAttr.NO_MOVE); 57 } 58 } 59 // Free the actual array structure 60 JudyLFreeArray(&array_, NO_ERROR); 61 } 62 63 // Is the array empty? 64 @property bool empty() const nothrow @nogc 65 { 66 return count == 0; 67 } 68 69 // Returns number of elements in the Judy array 70 @property size_t count() const nothrow @nogc 71 { 72 return JudyLCount(array_, 0, -1, NO_ERROR); 73 } 74 75 @property auto length() const nothrow @nogc 76 { 77 return size_t.sizeof; 78 } 79 80 // Returns the index and element of first entry. Throws range error if empty. 81 @property JudyLEntry front() 82 { 83 size_t index = 0; 84 auto value = cast(ElementType**)JudyLFirst(array_, &index, NO_ERROR); 85 86 if (value !is null) 87 { 88 return JudyLEntry(index, *value); 89 } 90 throw new RangeError(); 91 } 92 93 // Returns the index and element of first entry. Throws range error if empty. 94 @property const(JudyLEntry) front() const 95 { 96 size_t index = 0; 97 auto value = cast(ElementType**)JudyLFirst(array_, &index, NO_ERROR); 98 99 if (value !is null) 100 { 101 return JudyLEntry(index, *value); 102 } 103 throw new RangeError(); 104 } 105 106 // Removes first element. Throws RangeError if empty. 107 void popFront() 108 { 109 remove(first()); 110 } 111 112 // Gets index and element of last entry. Throws RangeError if empty. 113 @property JudyLEntry back() 114 { 115 size_t index = -1; 116 auto value = cast(ElementType**)JudyLLast(array_, &index, NO_ERROR); 117 118 if (value !is null) 119 { 120 return JudyLEntry(index, *value); 121 } 122 throw new RangeError(); 123 } 124 125 // Gets index and element of last entry. Throws RangeError if empty. 126 @property const(JudyLEntry) back() const 127 { 128 size_t index = -1; 129 auto value = cast(ElementType**)JudyLLast(array_, &index, NO_ERROR); 130 131 if (value !is null) 132 { 133 return JudyLEntry(index, *value); 134 } 135 throw new RangeError(); 136 } 137 138 // Removes last element. Throws RangeError if empty. 139 void popBack() 140 { 141 remove(last()); 142 } 143 144 // Create a slice over the underlying Judy array 145 auto opSlice() nothrow @nogc 146 { 147 return JudyLArrayRange!()(array_); 148 } 149 150 // Create a slice over the underlying Judy array 151 auto opSlice() const nothrow @nogc 152 { 153 return JudyLArrayRange!(true)(array_); 154 } 155 156 // Create a slice with given indices over the underlying Judy array 157 auto opSlice(const size_t start, const size_t end) nothrow @nogc 158 { 159 return JudyLArrayRange!()(array_, start, end); 160 } 161 162 // Create a slice with given indices over the underlying Judy array 163 auto opSlice(const size_t start, const size_t end) const nothrow @nogc 164 { 165 return JudyLArrayRange!(true)(array_, start, end); 166 } 167 168 // Return highest index of element in array 169 size_t opDollar() const 170 { 171 if (empty) 172 { 173 throw new RangeError(); 174 } 175 return back.index; 176 } 177 178 // Get element at index 179 ElementType opIndex(const size_t index) 180 { 181 return get(index); 182 } 183 184 // Get element at index 185 const(ElementType) opIndex(const size_t index) const 186 { 187 return get(index); 188 } 189 190 // Assign element to index 191 void opIndexAssign(ElementType value, const size_t index) 192 { 193 insert(index, value); 194 } 195 196 // Add element at index 197 void add(const size_t index, ElementType value) 198 { 199 insert(index, value); 200 } 201 202 // Remove element at index 203 bool remove(const size_t index) nothrow 204 { 205 ElementType element; 206 if (!at(index, element)) 207 { 208 return false; 209 } 210 211 auto deleted = JudyLDel(&array_, index, NO_ERROR) == 1; 212 213 // Remove explicit root from GC since instance is back under runtime 214 static if (UseGC && hasIndirections!ElementType) 215 { 216 if (deleted) 217 { 218 GC.removeRoot(cast(void*)element); 219 GC.clrAttr(cast(void*)element, GC.BlkAttr.NO_MOVE); 220 } 221 } 222 223 return deleted; 224 } 225 226 // Get element at. Return true if found. Places element into value. 227 bool at(const size_t index, out ElementType value) const nothrow @nogc 228 { 229 auto element = JudyLGet(array_, index, NO_ERROR); 230 if (element is null) 231 { 232 return false; 233 } 234 value = cast(ElementType)(*element); 235 return true; 236 } 237 238 // Check if has element at index 239 bool has(const size_t index) const nothrow @nogc 240 { 241 return JudyLGet(array_, index, NO_ERROR) !is null; 242 } 243 244 // Find first element >= index. Returns true if found, sets index and element. 245 bool first(ref size_t index, out ElementType found) const nothrow @nogc 246 { 247 auto value = cast(ElementType**)JudyLFirst(array_, &index, NO_ERROR); 248 if (value == null) 249 { 250 return false; 251 } 252 found = cast(ElementType)(*value); 253 return true; 254 } 255 256 // Find first elem >= index. Returns true if found. Sets index. 257 bool first(ref size_t index) const nothrow @nogc 258 { 259 return JudyLFirst(array_, &index, NO_ERROR) !is null; 260 } 261 262 // Get index of first element. Throws RangeError if empty. 263 size_t first() const 264 { 265 return front.index; 266 } 267 268 // Find next element > index. Returns true if found. Sets index and element. 269 bool next(ref size_t index, out ElementType found) const nothrow @nogc 270 { 271 auto value = cast(ElementType**)JudyLNext(array_, &index, NO_ERROR); 272 if (value == null) 273 { 274 return false; 275 } 276 found = cast(ElementType)(*value); 277 return true; 278 } 279 280 // Find next element > index. Returns true if found. Sets index. 281 bool next(ref size_t index) const nothrow @nogc 282 { 283 return JudyLNext(array_, &index, NO_ERROR) !is null; 284 } 285 286 // Find prev element < index. Returns true if found. Sets index and element. 287 bool prev(ref size_t index, out ElementType found) const nothrow @nogc 288 { 289 auto value = cast(ElementType**)JudyLPrev(array_, &index, NO_ERROR); 290 if (value == null) 291 { 292 return false; 293 } 294 found = cast(ElementType)(*value); 295 return true; 296 } 297 298 // Find prev element < index. Returns true if found. Sets index 299 bool prev(ref size_t index) const nothrow @nogc 300 { 301 return JudyLPrev(array_, &index, NO_ERROR) !is null; 302 } 303 304 // Find last element <= index. Returns true if found. Sets index and element. 305 bool last(ref size_t index, out ElementType found) const nothrow @nogc 306 { 307 auto value = cast(ElementType**)JudyLLast(array_, &index, NO_ERROR); 308 if (value == null) 309 { 310 return false; 311 } 312 found = cast(ElementType)(*value); 313 return true; 314 } 315 316 // Find last element <= index. Returns true if found. Sets index. 317 bool last(ref size_t index) const 318 { 319 return JudyLLast(array_, &index, NO_ERROR) !is null; 320 } 321 322 // Get index of last element. Throws RangeError if empty. 323 size_t last() const 324 { 325 return back.index; 326 } 327 328 329 // Find first empty slot >= index. Returns true if found. Sets index. 330 bool firstEmpty(ref size_t index) const nothrow @nogc 331 { 332 return JudyLFirstEmpty(array_, &index, NO_ERROR) == 1; 333 } 334 335 // Find next empty slot > index. Returns true if found. Sets index. 336 bool nextEmpty(ref size_t index) const nothrow @nogc 337 { 338 return JudyLNextEmpty(array_, &index, NO_ERROR) == 1; 339 } 340 341 // Find prev empty slot < index. Returns true if found. Sets index. 342 bool prevEmpty(ref size_t index) const nothrow @nogc 343 { 344 return JudyLPrevEmpty(array_, &index, NO_ERROR) == 1; 345 } 346 347 // Find last empty slot <= index. Returns true if found. Sets index. 348 bool lastEmpty(ref size_t index) const nothrow @nogc 349 { 350 return JudyLLastEmpty(array_, &index, NO_ERROR) == 1; 351 } 352 353 354 // Gets total amount of memory used by population and infrastructure 355 @property size_t memUsed() const nothrow @nogc 356 { 357 return JudyLMemUsed(array_); 358 } 359 360 // Gets total amount of memory used by population (pointers only) 361 @property size_t memActive() const nothrow @nogc 362 { 363 return JudyLMemActive(array_); 364 } 365 366 private: 367 void* array_; 368 369 // Insert element at index. Throws RangeError on insertion error. 370 void insert(const size_t index, ElementType value) 371 { 372 auto element = JudyLIns(&array_, index, NO_ERROR); 373 if (element is null) 374 { 375 throw new RangeError(); 376 } 377 378 // Add the element's address to the GC roots so it won't 379 // be collected 380 static if (UseGC && hasIndirections!ElementType) 381 { 382 GC.addRoot(cast(void*)value); 383 GC.setAttr(cast(void*)value, GC.BlkAttr.NO_MOVE); 384 } 385 386 *element = cast(ElementType*)value; 387 } 388 389 /* Get element at index. Throws RangeError if not found. See `at` 390 for exception safe version 391 */ 392 ElementType get(const size_t index) const 393 { 394 auto element = JudyLGet(array_, index, NO_ERROR); 395 if (element is null) 396 { 397 throw new RangeError(); 398 } 399 return cast(ElementType)(*element); 400 } 401 402 // An entry containing the index and element. Used for iteration 403 struct JudyLEntry 404 { 405 private: 406 const size_t index_; 407 ElementType* value_; 408 409 public: 410 this(const size_t index, ElementType* value) 411 { 412 this.index_ = index; 413 this.value_ = value; 414 } 415 416 @property size_t index() const nothrow @nogc 417 { 418 return index_; 419 } 420 421 @property inout(ElementType) value() inout nothrow @nogc 422 { 423 return cast(ElementType)(value_); 424 } 425 } 426 427 // Iteration struct, allows fast read only iteration of the underlying Judy array 428 struct JudyLArrayRange(bool isConst=false) 429 { 430 public: 431 // Construct slice over entire array 432 this(const void* array) nothrow @nogc 433 { 434 this(array, 0UL, -1UL); 435 } 436 437 // Construct slice over given range 438 this (const void* array, const size_t firstIndex, const size_t lastIndex) nothrow @nogc 439 { 440 array_ = array; 441 leftBound_ = firstIndex_ = firstIndex; 442 rightBound_ = lastIndex_ = lastIndex; 443 444 frontPtr_ = cast(ElementType**)JudyLFirst(array, &firstIndex_, NO_ERROR); 445 backPtr_ = cast(ElementType**)JudyLLast(array, &lastIndex_, NO_ERROR); 446 } 447 448 // Is slice empty? 449 @property bool empty() const nothrow @nogc 450 { 451 return frontPtr_ is null; 452 } 453 454 // Get first element/index of slice. 455 @property auto front() nothrow @nogc 456 in 457 { 458 assert(!empty); 459 } 460 body 461 { 462 static if (isConst) 463 { 464 return const(JudyLEntry)(firstIndex_, *frontPtr_); 465 } 466 else 467 { 468 return JudyLEntry(firstIndex_, *frontPtr_); 469 } 470 } 471 472 // Discard first element and find next 473 void popFront() nothrow @nogc 474 { 475 frontPtr_ = cast(ElementType**)JudyLNext(array_, &firstIndex_, NO_ERROR); 476 477 // Empty check 478 if (frontPtr_ is null) 479 { 480 backPtr_ = null; 481 } 482 } 483 484 // Get last element/index of slice. 485 @property auto back() nothrow @nogc 486 in 487 { 488 assert(!empty); 489 } 490 body 491 { 492 static if (isConst) 493 { 494 return const(JudyLEntry)(lastIndex_, *backPtr_); 495 } 496 else 497 { 498 return JudyLEntry(lastIndex_, *backPtr_); 499 } 500 } 501 502 // Discard last element of slice and find prev 503 void popBack() nothrow @nogc 504 { 505 backPtr_ = cast(ElementType**)JudyLPrev(array_, &lastIndex_, NO_ERROR); 506 507 // Empty check 508 if (backPtr_ is null) 509 { 510 frontPtr_ = null; 511 } 512 } 513 514 // Get element at index. Throws RangeError if out of bounds or not found. 515 auto opIndex(size_t index) const 516 { 517 if (index < leftBound_ || index > rightBound_) 518 { 519 throw new RangeError(); 520 } 521 522 auto element = cast(ElementType**)JudyLGet(array_, index, NO_ERROR); 523 524 if (element is null) 525 { 526 throw new RangeError(); 527 } 528 529 static if (isConst) 530 { 531 return cast(const(ElementType))*element; 532 } 533 else 534 { 535 return cast(ElementType)*element; 536 } 537 } 538 539 // Save iteration state 540 @property auto save() nothrow @nogc 541 { 542 return this; 543 } 544 545 // Get count of population in slice 546 @property auto count() const nothrow @nogc 547 { 548 return JudyLCount(array_, leftBound_, rightBound_, NO_ERROR); 549 } 550 551 @property auto length() const nothrow @nogc 552 { 553 return size_t.sizeof; 554 } 555 556 private: 557 ElementType** frontPtr_; 558 ElementType** backPtr_; 559 size_t leftBound_; 560 size_t rightBound_; 561 size_t firstIndex_; 562 size_t lastIndex_; 563 const void* array_; 564 } 565 566 static assert(isInputRange!JudyLArray); 567 568 static assert(isInputRange!(JudyLArrayRange!(false))); 569 static assert(isForwardRange!(JudyLArrayRange!(false))); 570 static assert(isBidirectionalRange!(JudyLArrayRange!(false))); 571 572 static assert(isInputRange!(JudyLArrayRange!(true))); 573 static assert(isForwardRange!(JudyLArrayRange!(true))); 574 static assert(isBidirectionalRange!(JudyLArrayRange!(true))); 575 } 576 577 578 579 version (unittest) 580 { 581 import std.algorithm; 582 import std.conv; 583 import std.exception; 584 import std.stdio; 585 586 class Data 587 { 588 public: 589 this(int x) 590 { 591 this.x = x; 592 } 593 594 int x; 595 } 596 597 struct Point 598 { 599 int x; 600 int y; 601 } 602 } 603 604 605 unittest 606 { 607 writeln("[UnitTest JudyL] - count"); 608 609 auto array = JudyLArray!Data(); 610 611 auto data = new Data(0); 612 613 assert(array.count == 0, "Array starting count is 0"); 614 615 array[0] = data; 616 assert(array.count == 1, "Array count updated"); 617 618 array[1] = data; 619 assert(array.count == 2, "Array count updated"); 620 621 array.remove(0); 622 assert(array.count == 1, "Array count updated"); 623 624 array.remove(1); 625 assert(array.count == 0, "Array count updated"); 626 } 627 628 unittest 629 { 630 writeln("[UnitTest JudyL] - empty"); 631 632 auto array = JudyLArray!Data(); 633 634 auto data = new Data(0); 635 636 assert(array.empty, "Array starts empty"); 637 638 array[0] = data; 639 assert(!array.empty, "Array not empty"); 640 641 array.add(1, data); 642 assert(!array.empty, "Array not empty"); 643 644 array.remove(0); 645 array.remove(1); 646 assert(array.empty, "Array now empty"); 647 } 648 649 unittest 650 { 651 writeln("[UnitTest JudyL] - has"); 652 653 auto array = JudyLArray!Data(); 654 655 auto data = new Data(0); 656 657 assert(!array.has(0), "Array doesn't have element"); 658 assert(!array.has(1), "Array doesn't have element"); 659 660 array[0] = data; 661 662 assert(array.has(0), "Array has element"); 663 assert(!array.has(1), "Array doesn't have element"); 664 665 array[1] = data; 666 667 assert(array.has(0), "Array has element"); 668 assert(array.has(1), "Array has element"); 669 } 670 671 unittest 672 { 673 writeln("[UnitTest JudyL] - at"); 674 675 { 676 auto array = JudyLArray!Data(); 677 678 auto data0 = new Data(0); 679 auto data1 = new Data(1); 680 681 Data value; 682 683 assert(!array.at(0, value), "Array doesn't have element"); 684 assert(!array.at(1, value), "Array doesn't have element"); 685 686 array[0] = data0; 687 array[1] = data1; 688 689 assert(array.at(0, value), "Array has element"); 690 assert(value == data0); 691 692 assert(array.at(1, value), "Array has element"); 693 assert(value == data1); 694 } 695 696 { 697 auto array = JudyLArray!(Point*)(); 698 699 auto point0 = new Point(0, 0); 700 auto point1 = new Point(1, 1); 701 702 Point* value; 703 704 assert(!array.at(0, value), "Array doesn't have element"); 705 assert(!array.at(1, value), "Array doesn't have element"); 706 707 array[0] = point0; 708 array[1] = point1; 709 710 assert(array.at(0, value), "Array has element"); 711 assert(value == point0); 712 713 assert(array.at(1, value), "Array has element"); 714 assert(value == point1); 715 } 716 } 717 718 unittest 719 { 720 writeln("[UnitTest JudyL] - add"); 721 722 auto array = JudyLArray!Data(); 723 724 auto data0 = new Data(0); 725 auto data1 = new Data(1); 726 727 array.add(0, data0); 728 array.add(1, data1); 729 730 assert(array[0] == data0, "Array has element"); 731 assert(array[1] == data1, "Array has element"); 732 733 array.add(0, data1); 734 assert(array[0] == data1, "Element updated"); 735 } 736 737 unittest 738 { 739 writeln("[UnitTest JudyL] - opIndexAssign"); 740 741 auto array = JudyLArray!Data(); 742 743 auto data0 = new Data(0); 744 auto data1 = new Data(1); 745 746 array.add(0, data0); 747 array.add(1, data1); 748 749 array[0] = data0; 750 assert(array[0] == data0, "Array has element"); 751 752 array[1] = data1; 753 assert(array[1] == data1, "Array has element"); 754 755 array[0] = data1; 756 assert(array[0] == data1, "Element updated"); 757 } 758 759 unittest 760 { 761 writeln("[UnitTest JudyL] - opIndex"); 762 763 auto array = JudyLArray!Data(); 764 765 auto data0 = new Data(0); 766 auto data1 = new Data(1); 767 768 assertThrown!RangeError(array[0], "Array doesn't have element"); 769 assertThrown!RangeError(array[1], "Array doesn't have element"); 770 771 array[0] = data0; 772 assert(array[0] == data0, "Array has element"); 773 774 array[1] = data1; 775 assert(array[1] == data1, "Array has element"); 776 } 777 778 unittest 779 { 780 writeln("[UnitTest JudyL] - remove"); 781 782 auto array = JudyLArray!Data(); 783 784 auto data = new Data(0); 785 786 assert(!array.remove(0), "Array doesn't have element"); 787 788 array[0] = data; 789 assert(array.remove(0), "Array had element"); 790 791 assert(!array.has(0), "Element removed"); 792 } 793 794 unittest 795 { 796 writeln("[UnitTest JudyL] - forward iteration"); 797 798 auto array = JudyLArray!Data(); 799 800 auto testrange = iota(100, 1000, 10); 801 802 Data[int] datas = assocArray( 803 zip( 804 testrange, 805 map!(a => new Data(a))(testrange).array 806 ) 807 ); 808 809 foreach(data; array) 810 { 811 assert(false, "Empty array"); 812 } 813 814 // Insert some elements 815 foreach(i; testrange) 816 { 817 array[i] = datas[i]; 818 } 819 820 auto j = 0; 821 foreach(ref data; array) 822 { 823 assert(data.index == testrange[j]); 824 assert(data.value == array[testrange[j++]]); 825 } 826 assert(array.count == testrange.length, "Forward iteration leaves data intact"); 827 } 828 829 unittest 830 { 831 writeln("[UnitTest JudyL] - forward const iteration"); 832 833 auto array = JudyLArray!Data(); 834 835 auto testrange = iota(100, 1000, 10); 836 837 Data[int] datas = assocArray( 838 zip( 839 testrange, 840 map!(a => new Data(a))(testrange).array 841 ) 842 ); 843 844 foreach(data; array) 845 { 846 assert(false, "Empty array"); 847 } 848 849 // Insert some elements 850 foreach(i; testrange) 851 { 852 array[i] = datas[i]; 853 } 854 855 auto cb = (const ref JudyLArray!Data array) 856 { 857 auto j = 0; 858 foreach(const data; array) 859 { 860 assert(data.index == testrange[j]); 861 assert(data.value == array[testrange[j++]]); 862 } 863 }; 864 865 cb(array); 866 867 assert(array.count == testrange.length, "Forward iteration leaves data intact"); 868 } 869 870 unittest 871 { 872 writeln("[UnitTest JudyL] - front and back"); 873 874 auto array = JudyLArray!Data(); 875 876 auto testrange = iota(100, 1000, 10); 877 878 Data[int] datas = assocArray( 879 zip( 880 testrange, 881 map!(a => new Data(a))(testrange).array 882 ) 883 ); 884 885 // Insert some elements 886 foreach(i; testrange) 887 { 888 array[i] = datas[i]; 889 } 890 891 // Verify front and back 892 assert(array.front.index == 100, "Correct front"); 893 assert(array.front.value == datas[100], "Correct front"); 894 assert(array.back.index == 990, "Correct back"); 895 assert(array.back.value == datas[990], "Correct back"); 896 897 898 // Remove front 899 array.remove(100); 900 assert(array.front.index == 110, "Front updated"); 901 assert(array.front.value == datas[110], "Front updated"); 902 assert(array.back.index == 990, "Back unchanged"); 903 assert(array.back.value == datas[990], "Back unchanged"); 904 905 // Remove back 906 array.remove(990); 907 assert(array.front.index == 110, "Front unchanged"); 908 assert(array.front.value == datas[110], "Front unchanged"); 909 assert(array.back.index == 980, "Back updated"); 910 assert(array.back.value == datas[980], "Back updated"); 911 912 // Remove middle 913 array.remove(550); 914 assert(array.front.index == 110, "Front unchanged"); 915 assert(array.front.value == datas[110], "Front unchanged"); 916 assert(array.back.index == 980, "Back updated"); 917 assert(array.back.value == datas[980], "Back updated"); 918 } 919 920 unittest 921 { 922 writeln("[UnitTest JudyL] - popFront and popBack"); 923 924 auto array = JudyLArray!Data(); 925 926 auto testrange = iota(0, 10); 927 928 Data[int] datas = assocArray( 929 zip( 930 testrange, 931 map!(a => new Data(a))(testrange).array 932 ) 933 ); 934 935 // Insert some elements 936 foreach(i; testrange) 937 { 938 array[i] = datas[i]; 939 } 940 941 auto first = array.first(); 942 943 auto second = first; 944 array.next(second); 945 946 auto last = array.last(); 947 948 auto second_last = last; 949 array.prev(second_last); 950 951 array.popFront(); 952 assert(!array.has(first), "Front removed"); 953 assert(array.front.index == second, "Front updated"); 954 assert(array.has(last), "Back unchanged"); 955 956 array.popBack(); 957 assert(!array.has(last), "Back removed"); 958 assert(array.back.index == second_last, "Back updated"); 959 assert(array.has(second), "Front unchanged"); 960 } 961 962 unittest 963 { 964 writeln("[UnitTest JudyL] - free memory"); 965 966 JudyLArray!Data* ptr; 967 968 { 969 auto array = JudyLArray!Data(); 970 971 assert(array.memUsed == 0, "No memory used on empty array"); 972 assert(array.memActive == 0, "No memory active on empty array"); 973 974 auto testrange = iota(0, 100); 975 976 Data[int] datas = assocArray( 977 zip( 978 testrange, 979 map!(a => new Data(a))(testrange).array 980 ) 981 ); 982 983 // Insert some elements 984 foreach(i; testrange) 985 { 986 array[i] = datas[i]; 987 } 988 989 assert(array.count == 100, "Count updated"); 990 assert(array.memUsed > 0, "Memory used"); 991 assert(array.memActive > 0, "Memory active"); 992 993 ptr = &array; 994 } 995 996 assert(ptr.count == 0, "Count cleared"); 997 assert(ptr.memUsed == 0, "Memory reclaimed"); 998 assert(ptr.memActive == 0, "Memory reclaimed"); 999 } 1000 1001 1002 unittest 1003 { 1004 writeln("[UnitTest JudyL] - opSlice"); 1005 1006 auto array = JudyLArray!Data(); 1007 1008 auto testrange = iota(0, 100); 1009 1010 Data[int] datas = assocArray( 1011 zip( 1012 testrange, 1013 map!(a => new Data(a))(testrange).array 1014 ) 1015 ); 1016 1017 // Test empty 1018 foreach(data; array[]) 1019 { 1020 assert(false, "empty array"); 1021 } 1022 1023 // Test one element 1024 array[1000] = datas[0]; 1025 int j = 0; 1026 foreach(ref data; array[]) 1027 { 1028 assert(j++ == 0, "Called once"); 1029 assert(data.index == 1000, "Index preserved"); 1030 assert(data.value == datas[0]); 1031 } 1032 array.remove(1000); 1033 1034 // Insert some elements 1035 foreach(i; testrange) 1036 { 1037 array[i] = datas[i]; 1038 } 1039 1040 assert(array.count == array[].count, "Array and slice count the same"); 1041 1042 j = 0; 1043 foreach(ref data; array[]) 1044 { 1045 assert(data.index == testrange[j]); 1046 assert(data.value == datas[j++], "Forward range iteration"); 1047 } 1048 1049 // backwards iteration 1050 j = testrange[$-1]; 1051 foreach(ref data; retro(array[])) 1052 { 1053 assert(data.index == testrange[j]); 1054 assert(data.value == datas[j--], "Retrograde range iteration"); 1055 } 1056 1057 auto slice = array[]; 1058 foreach(i; testrange) 1059 { 1060 assert(slice[i] == array[i], "Slice random access"); 1061 } 1062 1063 assertThrown!RangeError(slice[200], "Out of bounds"); 1064 1065 auto data1 = new Data(-7); 1066 auto data2 = new Data(-10); 1067 1068 array[50] = data1; 1069 array[10000] = data2; 1070 1071 assert(slice[50] == data1, "Array mutation reflected in slice"); 1072 assert(slice[10000] == data2, "Array insertion reflected in slice"); 1073 } 1074 1075 unittest 1076 { 1077 writeln("[UnitTest JudyL] - const opSlice"); 1078 1079 auto array = JudyLArray!Data(); 1080 1081 auto testrange = iota(0, 100); 1082 1083 Data[int] datas = assocArray( 1084 zip( 1085 testrange, 1086 map!(a => new Data(a))(testrange).array 1087 ) 1088 ); 1089 1090 // Insert some elements 1091 foreach(i; testrange) 1092 { 1093 array[i] = datas[i]; 1094 } 1095 1096 1097 array.front.value.x = 7; 1098 1099 auto testIt = delegate(const ref JudyLArray!Data constArray) 1100 { 1101 assert(array.count == constArray[].count, "Array and slice count the same"); 1102 1103 int j = 0; 1104 foreach(ref data; constArray[]) 1105 { 1106 assert(data.index == testrange[j]); 1107 assert(data.value == datas[j++], "Forward range iteration"); 1108 } 1109 1110 // backwards iteration 1111 j = testrange[$-1]; 1112 foreach(ref data; retro(constArray[])) 1113 { 1114 assert(data.index == testrange[j]); 1115 assert(data.value == datas[j--], "Retrograde range iteration"); 1116 } 1117 1118 auto slice = constArray[]; 1119 foreach(i; testrange) 1120 { 1121 assert(slice[i] == constArray[i], "Slice random access"); 1122 } 1123 1124 assertThrown!RangeError(slice[200], "Out of bounds"); 1125 1126 // can't modify the underlying element 1127 assert(!__traits(compiles, constArray[].front.value.x = 3)); 1128 }; 1129 1130 testIt(array); 1131 } 1132 1133 unittest 1134 { 1135 writeln("[UnitTest JudyL] - opSlice[x..y]"); 1136 1137 auto array = JudyLArray!Data(); 1138 1139 auto testrange = iota(0, 100); 1140 1141 Data[int] datas = assocArray( 1142 zip( 1143 testrange, 1144 map!(a => new Data(a))(testrange).array 1145 ) 1146 ); 1147 1148 // Test empty 1149 foreach(data; array[1..2]) 1150 { 1151 assert(false, "empty array"); 1152 } 1153 1154 // Test one element 1155 array[2] = datas[0]; 1156 int j = 0; 1157 foreach(ref data; array[0..5]) 1158 { 1159 assert(j == 0, "Called once"); 1160 assert(data.index == 2); 1161 assert(data.value == datas[0]); 1162 } 1163 array.remove(2); 1164 1165 // Insert some elements 1166 foreach(i; testrange) 1167 { 1168 array[i] = datas[i]; 1169 } 1170 1171 j = 20; 1172 foreach(ref data; array[20..30]) 1173 { 1174 assert(data.index == j); 1175 assert(data.value == datas[j++], "Indexed slice"); 1176 } 1177 1178 j = 20; 1179 foreach(ref data; array[20..500]) 1180 { 1181 assert(data.index == j); 1182 assert(data.value == datas[j++], "Indexed slice beyond population"); 1183 } 1184 1185 j = 90; 1186 foreach(ref data; array[90..$]) 1187 { 1188 assert(data.index == j); 1189 assert(data.value == datas[j++], "OpDollar slice"); 1190 } 1191 1192 j = 20; 1193 foreach(ref data; retro(array[10..20])) 1194 { 1195 assert(data.index == j); 1196 assert(data.value == datas[j--], "Retrograde slice"); 1197 } 1198 1199 auto slice = array[50..$]; 1200 foreach(i; 50..100) 1201 { 1202 assert(slice[i] == array[i], "Random access"); 1203 } 1204 1205 assertThrown!RangeError(array[10..20][9], "Out of bounds"); 1206 assertThrown!RangeError(array[10..20][21], "Out of bounds"); 1207 1208 auto data1 = new Data(-3); 1209 auto data2 = new Data(-4); 1210 1211 array[67] = data1; 1212 1213 assert(slice[67] == data1, "Array mutation reflected in slice"); 1214 } 1215 1216 unittest 1217 { 1218 writeln("[UnitTest JudyL] - opDollar"); 1219 1220 auto array = JudyLArray!Data(); 1221 1222 auto testrange = iota(0, 100, 5); 1223 1224 Data[int] datas = assocArray( 1225 zip( 1226 testrange, 1227 map!(a => new Data(a))(testrange).array 1228 ) 1229 ); 1230 1231 // Test empty 1232 assertThrown!RangeError(array[$]); 1233 1234 // Test one element 1235 array[0] = datas[0]; 1236 array[$] = datas[5]; 1237 assert(array[0] == datas[5]); 1238 array.remove(0); 1239 1240 1241 // Insert some elements 1242 foreach(i; testrange) 1243 { 1244 array[i] = datas[i]; 1245 } 1246 1247 array[$] = datas[0]; 1248 1249 assert(array[95] == datas[0], "opDollar is last index"); 1250 1251 auto data1 = new Data(77); 1252 array[size_t.max] = data1; 1253 1254 auto slice = array[95..$]; 1255 assert(slice.count == 2); 1256 assert(slice[95] == datas[0]); 1257 assert(slice[size_t.max] == data1); 1258 } 1259 1260 1261 unittest 1262 { 1263 writeln("[UnitTest JudyL] - find in empty array"); 1264 1265 auto array = JudyLArray!Data(); 1266 1267 Data found; 1268 size_t index = 0; 1269 assert(!array.first(index, found), "Empty array"); 1270 assert(!array.first(index), "Empty array"); 1271 assertThrown!RangeError(array.first(), "Empty array"); 1272 1273 index = 0; 1274 assert(!array.next(index, found), "Empty array"); 1275 assert(!array.next(index), "Empty array"); 1276 1277 index = -1; 1278 assert(!array.prev(index, found), "Empty array"); 1279 assert(!array.prev(index), "Empty array"); 1280 1281 index = -1; 1282 assert(!array.last(index, found), "Empty array"); 1283 assert(!array.last(index), "Empty array"); 1284 assertThrown!RangeError(array.last(), "Empty array"); 1285 } 1286 1287 unittest 1288 { 1289 writeln("[UnitTest JudyL] - find with single element at start"); 1290 1291 auto array = JudyLArray!Data(); 1292 1293 auto data = new Data(1); 1294 array[0] = data; 1295 1296 Data found; 1297 1298 1299 1300 size_t index = 0; 1301 assert(array.first(index, found)); 1302 assert(index == 0); 1303 assert(found == data); 1304 1305 index = 0; 1306 assert(array.first(index)); 1307 assert(index == 0); 1308 assert(array.first() == 0); 1309 1310 index = 0; 1311 assert(!array.next(index, found)); 1312 1313 index = 0; 1314 assert(!array.next(index)); 1315 1316 index = 0; 1317 assert(!array.prev(index, found)); 1318 1319 index = 0; 1320 assert(!array.prev(index)); 1321 1322 index = 0; 1323 assert(array.last(index, found)); 1324 assert(index == 0); 1325 assert(found == data); 1326 1327 index = 0; 1328 assert(array.last(index)); 1329 assert(index == 0); 1330 assert(array.last() == 0); 1331 1332 1333 1334 index = 1; 1335 assert(!array.first(index, found)); 1336 assert(!array.first(index)); 1337 1338 index = 1; 1339 assert(!array.next(index, found)); 1340 assert(!array.next(index)); 1341 1342 index = 1; 1343 assert(array.prev(index, found)); 1344 assert(index == 0); 1345 assert(found == data); 1346 1347 index = 1; 1348 assert(array.prev(index)); 1349 assert(index == 0); 1350 1351 index = 1; 1352 assert(array.last(index, found)); 1353 assert(index == 0); 1354 assert(found == data); 1355 1356 index = 1; 1357 assert(array.last(index)); 1358 assert(index == 0); 1359 1360 1361 1362 index = -1; 1363 assert(!array.first(index, found)); 1364 1365 index = -1; 1366 assert(!array.first(index)); 1367 1368 index = -1; 1369 assert(!array.next(index, found)); 1370 1371 index = -1; 1372 assert(!array.next(index)); 1373 1374 index = -1; 1375 assert(array.prev(index, found)); 1376 assert(index == 0); 1377 assert(found == data); 1378 1379 index = -1; 1380 assert(array.prev(index)); 1381 assert(index == 0); 1382 1383 index = -1; 1384 assert(array.last(index, found)); 1385 assert(index == 0); 1386 assert(found == data); 1387 1388 index = -1; 1389 assert(array.last(index)); 1390 assert(index == 0); 1391 1392 } 1393 1394 unittest 1395 { 1396 writeln("[UnitTest JudyL] - find with single element at end"); 1397 1398 auto array = JudyLArray!Data(); 1399 1400 const auto END = size_t.max; 1401 1402 auto data = new Data(0); 1403 array[END] = data; 1404 1405 Data found; 1406 1407 1408 1409 size_t index = 0; 1410 assert(array.first(index, found)); 1411 assert(index == END); 1412 assert(found == data); 1413 1414 index = 0; 1415 assert(array.first(index)); 1416 assert(index == END); 1417 assert(array.first() == END); 1418 1419 index = 0; 1420 assert(array.next(index, found)); 1421 assert(index == END); 1422 assert(found == data); 1423 1424 index = 0; 1425 assert(array.next(index)); 1426 assert(index == END); 1427 1428 index = 0; 1429 assert(!array.prev(index, found)); 1430 assert(!array.prev(index)); 1431 1432 index = 0; 1433 assert(!array.last(index, found)); 1434 1435 index = 0; 1436 assert(!array.last(index)); 1437 assert(array.last() == END); 1438 1439 1440 1441 index = END - 1; 1442 assert(array.first(index, found)); 1443 assert(index == END); 1444 assert(found == data); 1445 1446 index = END - 1; 1447 assert(array.first(index)); 1448 assert(index == END); 1449 1450 index = END - 1; 1451 assert(array.next(index, found)); 1452 assert(index == END); 1453 assert(found == data); 1454 1455 index = END - 1; 1456 assert(array.next(index)); 1457 assert(index == END); 1458 1459 index = END - 1; 1460 assert(!array.prev(index, found)); 1461 assert(!array.prev(index)); 1462 1463 index = END - 1; 1464 assert(!array.last(index, found)); 1465 assert(!array.last(index)); 1466 1467 1468 1469 index = -1; 1470 assert(array.first(index, found)); 1471 assert(index == END); 1472 assert(found == data); 1473 1474 index = -1; 1475 assert(array.first(index)); 1476 assert(index == END); 1477 1478 index = -1; 1479 assert(!array.next(index, found)); 1480 1481 index = -1; 1482 assert(!array.next(index)); 1483 1484 index = -1; 1485 assert(!array.prev(index, found)); 1486 1487 index = -1; 1488 assert(!array.prev(index)); 1489 1490 index = -1; 1491 assert(array.last(index, found)); 1492 assert(index == END); 1493 assert(found == data); 1494 1495 index = -1; 1496 assert(array.last(index)); 1497 assert(index == END); 1498 } 1499 1500 unittest 1501 { 1502 writeln("[UnitTest JudyL] - find with single element in middle"); 1503 1504 auto array = JudyLArray!Data(); 1505 1506 auto data = new Data(0); 1507 array[10] = data; 1508 1509 Data found; 1510 1511 1512 1513 size_t index = 0; 1514 assert(array.first(index, found)); 1515 assert(index == 10); 1516 assert(found == data); 1517 1518 index = 0; 1519 assert(array.first(index)); 1520 assert(index == 10); 1521 assert(array.first() == 10); 1522 1523 index = 0; 1524 assert(array.next(index, found)); 1525 assert(index == 10); 1526 assert(found == data); 1527 1528 index = 0; 1529 assert(array.next(index)); 1530 assert(index == 10); 1531 1532 index = 0; 1533 assert(!array.prev(index, found)); 1534 1535 index = 0; 1536 assert(!array.prev(index)); 1537 1538 index = 0; 1539 assert(!array.last(index, found)); 1540 1541 index = 0; 1542 assert(!array.last(index)); 1543 assert(array.last() == 10); 1544 1545 1546 1547 index = 10; 1548 assert(array.first(index, found)); 1549 assert(index == 10); 1550 assert(found == data); 1551 1552 index = 10; 1553 assert(array.first(index)); 1554 assert(index == 10); 1555 1556 index = 10; 1557 assert(!array.next(index, found)); 1558 assert(!array.next(index)); 1559 1560 index = 10; 1561 assert(!array.prev(index, found)); 1562 assert(!array.prev(index)); 1563 1564 index = 10; 1565 assert(array.last(index, found)); 1566 assert(index == 10); 1567 assert(found == data); 1568 1569 index = 10; 1570 assert(array.last(index)); 1571 assert(index == 10); 1572 1573 1574 1575 index = 11; 1576 assert(!array.first(index, found)); 1577 assert(!array.first(index)); 1578 1579 index = 11; 1580 assert(!array.next(index, found)); 1581 assert(!array.next(index)); 1582 1583 index = 11; 1584 assert(array.prev(index, found)); 1585 assert(index == 10); 1586 assert(found == data); 1587 1588 index = 11; 1589 assert(array.prev(index)); 1590 assert(index == 10); 1591 1592 index = 11; 1593 assert(array.last(index, found)); 1594 assert(index == 10); 1595 assert(found == data); 1596 1597 index = 11; 1598 assert(array.last(index)); 1599 assert(index == 10); 1600 1601 1602 1603 index = -1; 1604 assert(array.prev(index, found)); 1605 assert(index == 10); 1606 assert(found == data); 1607 1608 index = -1; 1609 assert(array.prev(index)); 1610 assert(index == 10); 1611 1612 index = -1; 1613 assert(array.last(index, found)); 1614 assert(index == 10); 1615 assert(found == data); 1616 1617 index = -1; 1618 assert(array.last(index)); 1619 assert(index == 10); 1620 } 1621 1622 unittest 1623 { 1624 writeln("[UnitTest JudyL] - find with multiple elements"); 1625 1626 auto array = JudyLArray!Data(); 1627 1628 auto data1 = new Data(0); 1629 auto data2 = new Data(1); 1630 1631 array[0] = data1; 1632 array[10] = data2; 1633 1634 Data found; 1635 1636 1637 1638 size_t index = 0; 1639 assert(array.first(index, found)); 1640 assert(index == 0); 1641 assert(found == data1); 1642 1643 index = 0; 1644 assert(array.first(index)); 1645 assert(index == 0); 1646 assert(array.first() == 0); 1647 1648 index = 0; 1649 assert(array.next(index, found)); 1650 assert(index == 10); 1651 assert(found == data2); 1652 1653 index = 0; 1654 assert(array.next(index)); 1655 assert(index == 10); 1656 1657 index = 0; 1658 assert(!array.prev(index, found)); 1659 1660 index = 0; 1661 assert(!array.prev(index)); 1662 1663 index = 0; 1664 assert(array.last(index, found)); 1665 assert(index == 0); 1666 assert(found == data1); 1667 1668 index = 0; 1669 assert(array.last(index)); 1670 assert(index == 0); 1671 assert(array.last() == 10); 1672 1673 1674 1675 index = 1; 1676 assert(array.first(index, found)); 1677 assert(index == 10); 1678 assert(found == data2); 1679 1680 index = 1; 1681 assert(array.first(index)); 1682 assert(index == 10); 1683 1684 index = 1; 1685 assert(array.next(index, found)); 1686 assert(index == 10); 1687 assert(found == data2); 1688 1689 index = 1; 1690 assert(array.next(index)); 1691 assert(index == 10); 1692 1693 index = 1; 1694 assert(array.prev(index, found)); 1695 assert(index == 0); 1696 assert(found == data1); 1697 1698 index = 1; 1699 assert(array.prev(index)); 1700 assert(index == 0); 1701 1702 index = 1; 1703 assert(array.last(index, found)); 1704 assert(index == 0); 1705 assert(found == data1); 1706 1707 index = 1; 1708 assert(array.last(index)); 1709 assert(index == 0); 1710 1711 1712 1713 index = 10; 1714 assert(array.first(index, found)); 1715 assert(index == 10); 1716 assert(found == data2); 1717 1718 index = 10; 1719 assert(array.first(index)); 1720 assert(index == 10); 1721 1722 index = 10; 1723 assert(!array.next(index, found)); 1724 assert(!array.next(index)); 1725 1726 index = 10; 1727 assert(array.prev(index, found)); 1728 assert(index == 0); 1729 assert(found == data1); 1730 1731 index = 10; 1732 assert(array.prev(index)); 1733 assert(index == 0); 1734 1735 index = 10; 1736 assert(array.last(index, found)); 1737 assert(index == 10); 1738 assert(found == data2); 1739 1740 index = 10; 1741 assert(array.last(index)); 1742 assert(index == 10); 1743 } 1744 1745 unittest 1746 { 1747 writeln("[UnitTest JudyL] - find empty in empty array"); 1748 1749 auto array = JudyLArray!Data(); 1750 1751 const auto END = size_t.max; 1752 1753 size_t index = 0; 1754 assert(array.firstEmpty(index), "Find first empty"); 1755 assert(index == 0); 1756 1757 index = 0; 1758 assert(array.nextEmpty(index), "Find next empty"); 1759 assert(index == 1); 1760 1761 index = -1; 1762 assert(array.prevEmpty(index), "Find prev empty"); 1763 assert(index == END - 1); 1764 1765 index = -1; 1766 assert(array.lastEmpty(index), "Find last empty"); 1767 assert(index == END); 1768 } 1769 1770 unittest 1771 { 1772 writeln("[UnitTest JudyL] - find empty with single element at start"); 1773 1774 auto array = JudyLArray!Data(); 1775 1776 const auto END = size_t.max; 1777 1778 auto data = new Data(0); 1779 array[0] = data; 1780 1781 size_t index = 0; 1782 assert(array.firstEmpty(index), "Find first empty"); 1783 assert(index == 1); 1784 1785 index = 0; 1786 assert(array.nextEmpty(index), "Find next empty"); 1787 assert(index == 1); 1788 1789 index = -1; 1790 assert(array.prevEmpty(index), "Find prev empty"); 1791 assert(index == END - 1); 1792 1793 index = -1; 1794 assert(array.lastEmpty(index), "Find last empty"); 1795 assert(index == END); 1796 } 1797 1798 unittest 1799 { 1800 writeln("[UnitTest JudyL] - find empty with single element at end"); 1801 1802 auto array = JudyLArray!Data(); 1803 1804 const auto END = size_t.max; 1805 1806 auto data = new Data(0); 1807 array[END] = data; 1808 1809 size_t index = END; 1810 assert(!array.firstEmpty(index), "Find first empty"); 1811 1812 index = END; 1813 assert(!array.nextEmpty(index), "Find next empty"); 1814 1815 index = -1; 1816 assert(array.prevEmpty(index), "Find prev empty"); 1817 assert(index == END - 1); 1818 1819 index = -1; 1820 assert(array.lastEmpty(index), "Find last empty"); 1821 assert(index == END - 1); 1822 } 1823 1824 unittest 1825 { 1826 writeln("[UnitTest JudyL] - find empty with single element in middle"); 1827 1828 auto array = JudyLArray!Data(); 1829 1830 const auto END = size_t.max; 1831 1832 auto data = new Data(0); 1833 array[10] = data; 1834 1835 size_t index = 0; 1836 assert(array.firstEmpty(index), "Find first empty"); 1837 assert(index == 0); 1838 1839 index = 0; 1840 assert(array.nextEmpty(index), "Find next empty"); 1841 assert(index == 1); 1842 1843 index = -1; 1844 assert(array.prevEmpty(index), "Find prev empty"); 1845 assert(index == END - 1); 1846 1847 index = -1; 1848 assert(array.lastEmpty(index), "Find last empty"); 1849 assert(index == END); 1850 1851 1852 1853 index = 9; 1854 assert(array.firstEmpty(index), "Find first empty"); 1855 assert(index == 9); 1856 1857 index = 9; 1858 assert(array.nextEmpty(index), "Find next empty"); 1859 assert(index == 11); 1860 1861 index = 11; 1862 assert(array.prevEmpty(index), "Find prev empty"); 1863 assert(index == 9); 1864 1865 index = 11; 1866 assert(array.lastEmpty(index), "Find last empty"); 1867 assert(index == 11); 1868 1869 1870 1871 index = 10; 1872 assert(array.firstEmpty(index), "Find first empty"); 1873 assert(index == 11); 1874 1875 index = 10; 1876 assert(array.nextEmpty(index), "Find next empty"); 1877 assert(index == 11); 1878 1879 index = 10; 1880 assert(array.prevEmpty(index), "Find prev empty"); 1881 assert(index == 9); 1882 1883 index = 10; 1884 assert(array.lastEmpty(index), "Find last empty"); 1885 assert(index == 9); 1886 } 1887 1888 unittest 1889 { 1890 writeln("[UnitTest JudyL] - struct pointer"); 1891 1892 auto array = JudyLArray!(Point*)(); 1893 1894 { 1895 auto point1 = new Point(1, 1); 1896 auto point2 = new Point(2, 2); 1897 1898 array[0] = point1; 1899 array[1] = point2; 1900 } 1901 1902 assert(array[0].x == 1); 1903 assert(array[0].y == 1); 1904 1905 assert(array[1].x == 2); 1906 assert(array[1].y == 2); 1907 1908 array.remove(0); 1909 array.remove(1); 1910 } 1911 1912 unittest 1913 { 1914 writeln("[UnitTest JudyL] - primitive pointer"); 1915 1916 auto array = JudyLArray!(int*)(); 1917 1918 { 1919 auto data1 = new int(7); 1920 auto data2 = new int(10); 1921 1922 array[0] = data1; 1923 array[1] = data2; 1924 } 1925 1926 assert(*array[0] == 7); 1927 assert(*array[1] == 10); 1928 1929 array.remove(0); 1930 array.remove(1); 1931 } 1932 1933 unittest 1934 { 1935 writeln("[UnitTest JudyL] - primitive"); 1936 1937 auto array = JudyLArray!(int)(); 1938 1939 { 1940 array[0] = 7; 1941 array[1] = 10; 1942 array[0] = 3; 1943 array[2] = array[0] * array[1]; 1944 } 1945 1946 assert(array[0] == 3); 1947 assert(array[1] == 10); 1948 assert(array[2] == 30); 1949 1950 array.remove(0); 1951 array.remove(1); 1952 } 1953 1954 unittest 1955 { 1956 writeln("[UnitTest JudyL] - type restrictions"); 1957 1958 assert(__traits(compiles, JudyLArray!Data), "Classes are allowed"); 1959 assert(__traits(compiles, JudyLArray!(Data*)), "Pointers to class are allowed"); 1960 assert(!__traits(compiles, JudyLArray!Point), "Structs are not allowed"); 1961 assert(__traits(compiles, JudyLArray!(Point*)), "Pointers to struct are allowed"); 1962 assert(!__traits(compiles, JudyLArray!(Data[])), "Arrays are not allowed"); 1963 assert(__traits(compiles, JudyLArray!(Data[]*)), "Pointers to arrays allowed"); 1964 1965 assert(__traits(compiles, JudyLArray!(long)), "long allowed"); 1966 assert(__traits(compiles, JudyLArray!(ulong)), "ulong allowed"); 1967 assert(__traits(compiles, JudyLArray!(int)), "int allowed"); 1968 assert(__traits(compiles, JudyLArray!(uint)), "uint allowed"); 1969 assert(__traits(compiles, JudyLArray!(short)), "short allowed"); 1970 assert(__traits(compiles, JudyLArray!(ushort)), "ushort allowed"); 1971 assert(__traits(compiles, JudyLArray!(double)), "double allowed"); 1972 assert(__traits(compiles, JudyLArray!(float)), "float allowed"); 1973 assert(__traits(compiles, JudyLArray!(byte)), "byte allowed"); 1974 assert(__traits(compiles, JudyLArray!(ubyte)), "ubyte allowed"); 1975 assert(__traits(compiles, JudyLArray!(char)), "char allowed"); 1976 assert(__traits(compiles, JudyLArray!(bool)), "bool allowed"); 1977 1978 assert(__traits(compiles, JudyLArray!(long*)), "long pointer allowed"); 1979 assert(__traits(compiles, JudyLArray!(ulong*)), "ulong pointer allowed"); 1980 assert(__traits(compiles, JudyLArray!(int*)), "int pointer allowed"); 1981 assert(__traits(compiles, JudyLArray!(uint*)), "uint pointer allowed"); 1982 assert(__traits(compiles, JudyLArray!(short*)), "short pointer allowed"); 1983 assert(__traits(compiles, JudyLArray!(ushort*)), "ushort pointer allowed"); 1984 assert(__traits(compiles, JudyLArray!(double*)), "double pointer allowed"); 1985 assert(__traits(compiles, JudyLArray!(float*)), "float pointer allowed"); 1986 assert(__traits(compiles, JudyLArray!(byte*)), "byte pointer allowed"); 1987 assert(__traits(compiles, JudyLArray!(ubyte*)), "ubyte pointer allowed"); 1988 assert(__traits(compiles, JudyLArray!(char*)), "char pointer allowed"); 1989 assert(__traits(compiles, JudyLArray!(bool*)), "bool pointer allowed"); 1990 }