1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /** 6 * Single-dimensioned array. 7 * 8 * Copyright: Eugene Wissner 2016-2021. 9 * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, 10 * Mozilla Public License, v. 2.0). 11 * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) 12 * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/container/array.d, 13 * tanya/container/array.d) 14 */ 15 module tanya.container.array; 16 17 import core.checkedint; 18 import std.algorithm.comparison; 19 import std.algorithm.iteration; 20 import std.algorithm.mutation : bringToFront; 21 import tanya.algorithm.mutation; 22 import tanya.memory.allocator; 23 import tanya.memory.lifetime; 24 import tanya.meta.trait; 25 import tanya.meta.transform; 26 import tanya.range; 27 28 /** 29 * Random-access range for the $(D_PSYMBOL Array). 30 * 31 * Params: 32 * A = Array type. 33 */ 34 struct Range(A) 35 { 36 private alias E = PointerTarget!(typeof(A.data)); 37 private E* begin, end; 38 private A* container; 39 40 invariant 41 { 42 assert(this.begin <= this.end); 43 assert(this.container !is null); 44 assert(this.begin >= this.container.data); 45 assert(this.end <= this.container.data + this.container.length); 46 } 47 48 private this(return ref A container, return E* begin, return E* end) 49 @trusted 50 in 51 { 52 assert(begin <= end); 53 assert(begin >= container.data); 54 assert(end <= container.data + container.length); 55 } 56 do 57 { 58 this.container = &container; 59 this.begin = begin; 60 this.end = end; 61 } 62 63 @disable this(); 64 65 @property Range save() 66 { 67 return this; 68 } 69 70 @property bool empty() const 71 { 72 return this.begin == this.end; 73 } 74 75 @property size_t length() const 76 { 77 return this.end - this.begin; 78 } 79 80 alias opDollar = length; 81 82 @property ref inout(E) front() inout 83 in 84 { 85 assert(!empty); 86 } 87 do 88 { 89 return *this.begin; 90 } 91 92 @property ref inout(E) back() inout @trusted 93 in 94 { 95 assert(!empty); 96 } 97 do 98 { 99 return *(this.end - 1); 100 } 101 102 void popFront() @trusted 103 in 104 { 105 assert(!empty); 106 } 107 do 108 { 109 ++this.begin; 110 } 111 112 void popBack() @trusted 113 in 114 { 115 assert(!empty); 116 } 117 do 118 { 119 --this.end; 120 } 121 122 ref inout(E) opIndex(size_t i) inout @trusted 123 in 124 { 125 assert(i < length); 126 } 127 do 128 { 129 return *(this.begin + i); 130 } 131 132 Range opIndex() 133 { 134 return typeof(return)(*this.container, this.begin, this.end); 135 } 136 137 A.ConstRange opIndex() const 138 { 139 return typeof(return)(*this.container, this.begin, this.end); 140 } 141 142 Range opSlice(size_t i, size_t j) @trusted 143 in 144 { 145 assert(i <= j); 146 assert(j <= length); 147 } 148 do 149 { 150 return typeof(return)(*this.container, this.begin + i, this.begin + j); 151 } 152 153 A.ConstRange opSlice(size_t i, size_t j) const @trusted 154 in 155 { 156 assert(i <= j); 157 assert(j <= length); 158 } 159 do 160 { 161 return typeof(return)(*this.container, this.begin + i, this.begin + j); 162 } 163 164 inout(E)[] get() inout 165 { 166 return this.begin[0 .. length]; 167 } 168 } 169 170 /** 171 * One dimensional array. 172 * 173 * Params: 174 * T = Content type. 175 */ 176 struct Array(T) 177 { 178 /// The range types for $(D_PSYMBOL Array). 179 alias Range = .Range!Array; 180 181 /// ditto 182 alias ConstRange = .Range!(const Array); 183 184 private size_t length_; 185 private T* data; 186 private size_t capacity_; 187 188 invariant 189 { 190 assert(this.length_ <= this.capacity_); 191 assert(this.capacity_ == 0 || this.data !is null); 192 } 193 194 /** 195 * Creates a new $(D_PSYMBOL Array) with the elements from a static array. 196 * 197 * Params: 198 * R = Static array size. 199 * init = Values to initialize the array with. 200 * allocator = Allocator. 201 */ 202 this(size_t R)(T[R] init, shared Allocator allocator = defaultAllocator) 203 { 204 this(allocator); 205 insertBack!(T[])(init[]); 206 } 207 208 /** 209 * Creates a new $(D_PSYMBOL Array) with the elements from an input range. 210 * 211 * Params: 212 * R = Type of the initial range. 213 * init = Values to initialize the array with. 214 * allocator = Allocator. 215 */ 216 this(R)(scope R init, shared Allocator allocator = defaultAllocator) 217 if (!isInfinite!R 218 && isInputRange!R 219 && isImplicitlyConvertible!(ElementType!R, T)) 220 { 221 this(allocator); 222 insertBack(init); 223 } 224 225 /** 226 * Initializes this array from another one. 227 * 228 * If $(D_PARAM init) is passed by value, it won't be copied, but moved. 229 * If the allocator of ($D_PARAM init) matches $(D_PARAM allocator), 230 * $(D_KEYWORD this) will just take the ownership over $(D_PARAM init)'s 231 * storage, otherwise, the storage will be allocated with 232 * $(D_PARAM allocator) and all elements will be moved; 233 * $(D_PARAM init) will be destroyed at the end. 234 * 235 * If $(D_PARAM init) is passed by reference, it will be copied. 236 * 237 * Params: 238 * R = Source array type. 239 * init = Source array. 240 * allocator = Allocator. 241 */ 242 this(R)(ref R init, shared Allocator allocator = defaultAllocator) 243 if (is(Unqual!R == Array)) 244 { 245 this(allocator); 246 insertBack(init[]); 247 } 248 249 /// ditto 250 this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted 251 if (is(R == Array)) 252 { 253 this(allocator); 254 if (allocator is init.allocator) 255 { 256 // Just steal all references and the allocator. 257 this.data = init.data; 258 this.length_ = init.length_; 259 this.capacity_ = init.capacity_; 260 261 // Reset the source array, so it can't destroy the moved storage. 262 init.length_ = init.capacity_ = 0; 263 init.data = null; 264 } 265 else 266 { 267 // Move each element. 268 reserve(init.length_); 269 foreach (ref target; slice(init.length_)) 270 { 271 moveEmplace(*init.data++, target); 272 } 273 this.length_ = init.length_; 274 // Destructor of init should destroy it here. 275 } 276 } 277 278 /// 279 @nogc nothrow pure @safe unittest 280 { 281 auto v1 = Array!int([1, 2, 3]); 282 auto v2 = Array!int(v1); 283 assert(v1 == v2); 284 285 auto v3 = Array!int(Array!int([1, 2, 3])); 286 assert(v1 == v3); 287 assert(v3.length == 3); 288 assert(v3.capacity == 3); 289 } 290 291 /** 292 * Creates a new $(D_PSYMBOL Array). 293 * 294 * Params: 295 * len = Initial length of the array. 296 * init = Initial value to fill the array with. 297 * allocator = Allocator. 298 */ 299 this()(size_t len, 300 auto ref T init, 301 shared Allocator allocator = defaultAllocator) 302 { 303 this(allocator); 304 reserve(len); 305 uninitializedFill(slice(len), init); 306 length_ = len; 307 } 308 309 /// ditto 310 this(size_t len, shared Allocator allocator = defaultAllocator) 311 { 312 this(allocator); 313 length = len; 314 } 315 316 /// ditto 317 this(shared Allocator allocator) 318 in 319 { 320 assert(allocator !is null); 321 } 322 do 323 { 324 allocator_ = allocator; 325 } 326 327 /// 328 @nogc nothrow pure @safe unittest 329 { 330 auto v = Array!int([3, 8, 2]); 331 332 assert(v.capacity == 3); 333 assert(v.length == 3); 334 assert(v[0] == 3 && v[1] == 8 && v[2] == 2); 335 } 336 337 /// 338 @nogc nothrow pure @safe unittest 339 { 340 auto v = Array!int(3, 5); 341 342 assert(v.capacity == 3); 343 assert(v.length == 3); 344 assert(v[0] == 5 && v[1] == 5 && v[2] == 5); 345 } 346 347 /** 348 * Destroys this $(D_PSYMBOL Array). 349 */ 350 ~this() 351 { 352 destroyAll(slice(this.length_)); 353 deallocate(); 354 } 355 356 private void deallocate() @trusted 357 { 358 allocator.deallocate(slice(capacity)); 359 } 360 361 static if (isCopyable!T) 362 { 363 this(this) 364 { 365 auto buf = slice(this.length); 366 this.length_ = capacity_ = 0; 367 this.data = null; 368 insertBack(buf); 369 } 370 } 371 else 372 { 373 @disable this(this); 374 } 375 376 /** 377 * Removes all elements. 378 */ 379 void clear() 380 { 381 length = 0; 382 } 383 384 /// 385 @nogc nothrow pure @safe unittest 386 { 387 auto v = Array!int([18, 20, 15]); 388 v.clear(); 389 assert(v.length == 0); 390 assert(v.capacity == 3); 391 } 392 393 /** 394 * Returns: How many elements the array can contain without reallocating. 395 */ 396 @property size_t capacity() const 397 { 398 return capacity_; 399 } 400 401 /// 402 @nogc nothrow pure @safe unittest 403 { 404 auto v = Array!int(4); 405 assert(v.capacity == 4); 406 } 407 408 /** 409 * Returns: Array length. 410 */ 411 @property size_t length() const 412 { 413 return length_; 414 } 415 416 /// ditto 417 size_t opDollar() const 418 { 419 return length; 420 } 421 422 /** 423 * Expands/shrinks the array. 424 * 425 * Params: 426 * len = New length. 427 */ 428 @property void length(size_t len) @trusted 429 { 430 if (len > length) 431 { 432 reserve(len); 433 initializeAll(this.data[length_ .. len]); 434 } 435 else 436 { 437 destroyAll(this.data[len .. this.length_]); 438 } 439 if (len != length) 440 { 441 length_ = len; 442 } 443 } 444 445 /// 446 @nogc nothrow pure @safe unittest 447 { 448 Array!int v; 449 450 v.length = 5; 451 assert(v.length == 5); 452 assert(v.capacity == 5); 453 454 v.length = 7; 455 assert(v.length == 7); 456 assert(v.capacity == 7); 457 458 assert(v[$ - 1] == 0); 459 v[$ - 1] = 3; 460 assert(v[$ - 1] == 3); 461 462 v.length = 0; 463 assert(v.length == 0); 464 assert(v.capacity == 7); 465 } 466 467 /** 468 * Reserves space for $(D_PARAM size) elements. 469 * 470 * If $(D_PARAM size) is less than or equal to the $(D_PSYMBOL capacity), the 471 * function call does not cause a reallocation and the array capacity is not 472 * affected. 473 * 474 * Params: 475 * size = Desired size. 476 */ 477 void reserve(size_t size) @trusted 478 { 479 if (capacity_ >= size) 480 { 481 return; 482 } 483 bool overflow; 484 const byteSize = mulu(size, T.sizeof, overflow); 485 assert(!overflow); 486 487 void[] buf = this.data[0 .. this.capacity_]; 488 if (!allocator.reallocateInPlace(buf, byteSize)) 489 { 490 buf = allocator.allocate(byteSize); 491 if (buf is null) 492 { 493 onOutOfMemoryError(); 494 } 495 scope (failure) 496 { 497 allocator.deallocate(buf); 498 } 499 for (T* src = this.data, dest = cast(T*) buf; src != end; ++src, ++dest) 500 { 501 moveEmplace(*src, *dest); 502 static if (hasElaborateDestructor!T) 503 { 504 destroy(*src); 505 } 506 } 507 deallocate(); 508 this.data = cast(T*) buf; 509 } 510 this.capacity_ = size; 511 } 512 513 /// 514 @nogc nothrow pure @safe unittest 515 { 516 Array!int v; 517 assert(v.capacity == 0); 518 assert(v.length == 0); 519 520 v.reserve(3); 521 assert(v.capacity == 3); 522 assert(v.length == 0); 523 } 524 525 /** 526 * Requests the array to reduce its capacity to fit the $(D_PARAM size). 527 * 528 * The request is non-binding. The array won't become smaller than the 529 * $(D_PARAM length). 530 * 531 * Params: 532 * size = Desired size. 533 */ 534 void shrink(size_t size) @trusted 535 { 536 if (capacity <= size) 537 { 538 return; 539 } 540 const n = max(length, size); 541 void[] buf = slice(this.capacity_); 542 if (allocator.reallocateInPlace(buf, n * T.sizeof)) 543 { 544 this.capacity_ = n; 545 } 546 } 547 548 /// 549 @nogc nothrow pure @safe unittest 550 { 551 Array!int v; 552 assert(v.capacity == 0); 553 assert(v.length == 0); 554 555 v.reserve(5); 556 v.insertBack(1); 557 v.insertBack(3); 558 assert(v.capacity == 5); 559 assert(v.length == 2); 560 } 561 562 /** 563 * Returns: $(D_KEYWORD true) if the array is empty. 564 */ 565 @property bool empty() const 566 { 567 return length == 0; 568 } 569 570 /** 571 * Removes the value at the back of the array. 572 * 573 * Returns: The number of elements removed 574 * 575 * Precondition: $(D_INLINECODE !empty). 576 */ 577 void removeBack() 578 in 579 { 580 assert(!empty); 581 } 582 do 583 { 584 length = length - 1; 585 } 586 587 /** 588 * Removes $(D_PARAM howMany) elements from the array. 589 * 590 * This method doesn't fail if it could not remove $(D_PARAM howMany) 591 * elements. Instead, if $(D_PARAM howMany) is greater than the array 592 * length, all elements are removed. 593 * 594 * Params: 595 * howMany = How many elements should be removed. 596 * 597 * Returns: The number of elements removed 598 */ 599 size_t removeBack(size_t howMany) 600 out (removed) 601 { 602 assert(removed <= howMany); 603 } 604 do 605 { 606 const toRemove = min(howMany, length); 607 608 length = length - toRemove; 609 610 return toRemove; 611 } 612 613 /// 614 @nogc nothrow pure @safe unittest 615 { 616 auto v = Array!int([5, 18, 17]); 617 618 assert(v.removeBack(0) == 0); 619 assert(v.removeBack(2) == 2); 620 assert(v.removeBack(3) == 1); 621 assert(v.removeBack(3) == 0); 622 } 623 624 private inout(T)[] slice(size_t length) inout @trusted 625 in 626 { 627 assert(length <= capacity); 628 } 629 do 630 { 631 return this.data[0 .. length]; 632 } 633 634 private @property inout(T)* end() inout @trusted 635 { 636 return this.data + this.length_; 637 } 638 639 /** 640 * Remove all elements beloning to $(D_PARAM r). 641 * 642 * Params: 643 * r = Range originally obtained from this array. 644 * 645 * Returns: A range spanning the remaining elements in the array that 646 * initially were right after $(D_PARAM r). 647 * 648 * Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this). 649 */ 650 Range remove(scope Range r) 651 in 652 { 653 assert(r.container is &this); 654 assert(r.begin >= this.data); 655 assert(r.end <= end); 656 } 657 do 658 { 659 auto target = r.begin; 660 auto source = r.end; 661 while (source !is end) 662 { 663 move(*source, *target); 664 ((ref s, ref t) @trusted {++s; ++t;})(source, target); 665 } 666 length = length - r.length; 667 return Range(this, r.begin, end); 668 } 669 670 /// 671 @nogc nothrow pure @safe unittest 672 { 673 auto v = Array!int([5, 18, 17, 2, 4, 6, 1]); 674 675 assert(v.remove(v[1 .. 3]).length == 4); 676 assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6 && v[4] == 1); 677 assert(v.length == 5); 678 679 assert(v.remove(v[4 .. 4]).length == 1); 680 assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6 && v[4] == 1); 681 assert(v.length == 5); 682 683 assert(v.remove(v[4 .. 5]).length == 0); 684 assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6); 685 assert(v.length == 4); 686 687 assert(v.remove(v[]).length == 0); 688 689 } 690 691 private void moveBack(R)(ref R el) @trusted 692 if (isImplicitlyConvertible!(R, T)) 693 { 694 reserve(this.length + 1); 695 moveEmplace(el, *end); 696 ++this.length_; 697 } 698 699 /** 700 * Inserts the $(D_PARAM el) into the array. 701 * 702 * Params: 703 * R = Type of the inserted value(s) (single value, range or static array). 704 * el = Value(s) should be inserted. 705 * 706 * Returns: The number of elements inserted. 707 */ 708 size_t insertBack(R)(R el) 709 if (isImplicitlyConvertible!(R, T)) 710 { 711 moveBack(el); 712 return 1; 713 } 714 715 /// ditto 716 size_t insertBack(R)(ref R el) 717 if (isImplicitlyConvertible!(R, T)) 718 { 719 length = length + 1; 720 scope (failure) 721 { 722 length = length - 1; 723 } 724 opIndex(this.length - 1) = el; 725 return 1; 726 } 727 728 /// ditto 729 size_t insertBack(R)(scope R el) 730 if (!isInfinite!R 731 && isInputRange!R 732 && isImplicitlyConvertible!(ElementType!R, T)) 733 { 734 static if (hasLength!R) 735 { 736 reserve(length + el.length); 737 } 738 return fold!((acc, e) => acc + insertBack(e))(el, size_t.init); 739 } 740 741 /// ditto 742 size_t insertBack(size_t R)(T[R] el) 743 { 744 return insertBack!(T[])(el[]); 745 } 746 747 /// ditto 748 alias insert = insertBack; 749 750 /// 751 @nogc nothrow pure @safe unittest 752 { 753 struct TestRange 754 { 755 int counter = 6; 756 757 int front() 758 { 759 return counter; 760 } 761 762 void popFront() 763 { 764 counter -= 2; 765 } 766 767 bool empty() 768 { 769 return counter == 0; 770 } 771 } 772 773 Array!int v1; 774 775 assert(v1.insertBack(5) == 1); 776 assert(v1.length == 1); 777 assert(v1.capacity == 1); 778 assert(v1.back == 5); 779 780 assert(v1.insertBack(TestRange()) == 3); 781 assert(v1.length == 4); 782 assert(v1.capacity == 4); 783 assert(v1[0] == 5 && v1[1] == 6 && v1[2] == 4 && v1[3] == 2); 784 785 assert(v1.insertBack([34, 234]) == 2); 786 assert(v1.length == 6); 787 assert(v1.capacity == 6); 788 assert(v1[4] == 34 && v1[5] == 234); 789 } 790 791 /** 792 * Inserts $(D_PARAM el) before or after $(D_PARAM r). 793 * 794 * Params: 795 * R = Type of the inserted value(s) (single value, range or static array). 796 * r = Range originally obtained from this array. 797 * el = Value(s) should be inserted. 798 * 799 * Returns: The number of elements inserted. 800 * 801 * Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this). 802 */ 803 size_t insertAfter(R)(Range r, scope R el) 804 if (!isInfinite!R 805 && isInputRange!R 806 && isImplicitlyConvertible!(ElementType!R, T)) 807 in 808 { 809 assert(r.container is &this); 810 assert(r.begin >= this.data); 811 assert(r.end <= this.data + length); 812 } 813 do 814 { 815 const oldLength = length; 816 const after = r.end - this.data; 817 const inserted = insertBack(el); 818 819 bringToFront(this.data[after .. oldLength], this.data[oldLength .. length]); 820 return inserted; 821 } 822 823 /// ditto 824 size_t insertAfter(size_t R)(Range r, T[R] el) 825 in 826 { 827 assert(r.container is &this); 828 assert(r.begin >= this.data); 829 assert(r.end <= this.data + length); 830 } 831 do 832 { 833 return insertAfter!(T[])(r, el[]); 834 } 835 836 /// ditto 837 size_t insertAfter(R)(Range r, auto ref R el) 838 if (isImplicitlyConvertible!(R, T)) 839 in 840 { 841 assert(r.container is &this); 842 assert(r.begin >= this.data); 843 assert(r.end <= this.data + length); 844 } 845 do 846 { 847 const oldLen = length; 848 const offset = r.end - this.data; 849 850 static if (__traits(isRef, el)) 851 { 852 insertBack(el); 853 } 854 else 855 { 856 moveBack(el); 857 } 858 bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]); 859 860 return 1; 861 } 862 863 /// ditto 864 size_t insertBefore(R)(Range r, scope R el) 865 if (!isInfinite!R 866 && isInputRange!R 867 && isImplicitlyConvertible!(ElementType!R, T)) 868 in 869 { 870 assert(r.container is &this); 871 assert(r.begin >= this.data); 872 assert(r.end <= this.data + length); 873 } 874 do 875 { 876 return insertAfter(Range(this, this.data, r.begin), el); 877 } 878 879 /// ditto 880 size_t insertBefore(size_t R)(Range r, T[R] el) 881 in 882 { 883 assert(r.container is &this); 884 assert(r.begin >= this.data); 885 assert(r.end <= this.data + length); 886 } 887 do 888 { 889 return insertBefore!(T[])(r, el[]); 890 } 891 892 /// ditto 893 size_t insertBefore(R)(Range r, auto ref R el) 894 if (isImplicitlyConvertible!(R, T)) 895 in 896 { 897 assert(r.container is &this); 898 assert(r.begin >= this.data); 899 assert(r.end <= this.data + length); 900 } 901 do 902 { 903 const oldLen = length; 904 const offset = r.begin - this.data; 905 906 static if (__traits(isRef, el)) 907 { 908 insertBack(el); 909 } 910 else 911 { 912 moveBack(el); 913 } 914 bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]); 915 916 return 1; 917 } 918 919 /// 920 @nogc nothrow pure unittest 921 { 922 Array!int v1; 923 v1.insertAfter(v1[], [2, 8]); 924 assert(v1[0] == 2); 925 assert(v1[1] == 8); 926 assert(v1.length == 2); 927 928 v1.insertAfter(v1[], [1, 2]); 929 assert(v1[0] == 2); 930 assert(v1[1] == 8); 931 assert(v1[2] == 1); 932 assert(v1[3] == 2); 933 assert(v1.length == 4); 934 935 v1.insertAfter(v1[0 .. 0], [1, 2]); 936 assert(v1[0] == 1); 937 assert(v1[1] == 2); 938 assert(v1[2] == 2); 939 assert(v1[3] == 8); 940 assert(v1[4] == 1); 941 assert(v1[5] == 2); 942 assert(v1.length == 6); 943 944 v1.insertAfter(v1[0 .. 4], 9); 945 assert(v1[0] == 1); 946 assert(v1[1] == 2); 947 assert(v1[2] == 2); 948 assert(v1[3] == 8); 949 assert(v1[4] == 9); 950 assert(v1[5] == 1); 951 assert(v1[6] == 2); 952 assert(v1.length == 7); 953 } 954 955 /// 956 @nogc nothrow pure unittest 957 { 958 Array!int v1; 959 v1.insertBefore(v1[], [2, 8]); 960 assert(v1[0] == 2); 961 assert(v1[1] == 8); 962 assert(v1.length == 2); 963 964 v1.insertBefore(v1[], [1, 2]); 965 assert(v1[0] == 1); 966 assert(v1[1] == 2); 967 assert(v1[2] == 2); 968 assert(v1[3] == 8); 969 assert(v1.length == 4); 970 971 v1.insertBefore(v1[0 .. 1], [1, 2]); 972 assert(v1[0] == 1); 973 assert(v1[1] == 2); 974 assert(v1[2] == 1); 975 assert(v1[3] == 2); 976 assert(v1[4] == 2); 977 assert(v1[5] == 8); 978 assert(v1.length == 6); 979 980 v1.insertBefore(v1[2 .. $], 9); 981 assert(v1[0] == 1); 982 assert(v1[1] == 2); 983 assert(v1[2] == 9); 984 assert(v1[3] == 1); 985 assert(v1[4] == 2); 986 assert(v1[5] == 2); 987 assert(v1[6] == 8); 988 assert(v1.length == 7); 989 } 990 991 /** 992 * Assigns a value to the element with the index $(D_PARAM pos). 993 * 994 * Params: 995 * E = Value type. 996 * value = Value. 997 * pos = Position. 998 * 999 * Returns: Assigned value. 1000 * 1001 * Precondition: $(D_INLINECODE length > pos). 1002 */ 1003 ref T opIndexAssign(E : T)(auto ref E value, size_t pos) 1004 { 1005 return opIndex(pos) = forward!value; 1006 } 1007 1008 /// ditto 1009 Range opIndexAssign(E : T)(auto ref E value) 1010 { 1011 return opSliceAssign(value, 0, length); 1012 } 1013 1014 /// 1015 @nogc nothrow pure @safe unittest 1016 { 1017 Array!int a = Array!int(1); 1018 a[0] = 5; 1019 assert(a[0] == 5); 1020 } 1021 1022 /** 1023 * Assigns a range or a static array. 1024 * 1025 * Params: 1026 * R = Value type. 1027 * value = Value. 1028 * 1029 * Returns: Assigned value. 1030 * 1031 * Precondition: $(D_INLINECODE length == value.length). 1032 */ 1033 Range opIndexAssign(size_t R)(T[R] value) 1034 { 1035 return opSliceAssign!R(value, 0, length); 1036 } 1037 1038 /// ditto 1039 Range opIndexAssign()(Range value) 1040 { 1041 return opSliceAssign(value, 0, length); 1042 } 1043 1044 /// 1045 @nogc nothrow pure @safe unittest 1046 { 1047 auto v1 = Array!int([12, 1, 7]); 1048 1049 v1[] = 3; 1050 assert(v1[0] == 3); 1051 assert(v1[1] == 3); 1052 assert(v1[2] == 3); 1053 1054 v1[] = [7, 1, 12]; 1055 assert(v1[0] == 7); 1056 assert(v1[1] == 1); 1057 assert(v1[2] == 12); 1058 } 1059 1060 /** 1061 * Params: 1062 * pos = Index. 1063 * 1064 * Returns: The value at a specified index. 1065 * 1066 * Precondition: $(D_INLINECODE length > pos). 1067 */ 1068 ref inout(T) opIndex(size_t pos) inout @trusted 1069 in 1070 { 1071 assert(length > pos); 1072 } 1073 do 1074 { 1075 return *(this.data + pos); 1076 } 1077 1078 /** 1079 * Returns: Random access range that iterates over elements of the array, 1080 * in forward order. 1081 */ 1082 Range opIndex() @trusted 1083 { 1084 return typeof(return)(this, this.data, this.data + length); 1085 } 1086 1087 /// ditto 1088 ConstRange opIndex() const @trusted 1089 { 1090 return typeof(return)(this, this.data, this.data + length); 1091 } 1092 1093 /// 1094 @nogc nothrow pure @safe unittest 1095 { 1096 const v1 = Array!int([6, 123, 34, 5]); 1097 1098 assert(v1[0] == 6); 1099 assert(v1[1] == 123); 1100 assert(v1[2] == 34); 1101 assert(v1[3] == 5); 1102 static assert(is(typeof(v1[0]) == const(int))); 1103 static assert(is(typeof(v1[]))); 1104 } 1105 1106 /** 1107 * Comparison for equality. 1108 * 1109 * Params: 1110 * that = The array to compare with. 1111 * 1112 * Returns: $(D_KEYWORD true) if the arrays are equal, $(D_KEYWORD false) 1113 * otherwise. 1114 */ 1115 bool opEquals()(auto ref typeof(this) that) @trusted 1116 { 1117 return equal(this.data[0 .. length], that.data[0 .. that.length]); 1118 } 1119 1120 /// ditto 1121 bool opEquals()(auto ref const typeof(this) that) const @trusted 1122 { 1123 return equal(this.data[0 .. length], that.data[0 .. that.length]); 1124 } 1125 1126 /// ditto 1127 bool opEquals(R)(R that) 1128 if (is(R == Range)) 1129 { 1130 return equal(opIndex(), that); 1131 } 1132 1133 /** 1134 * Comparison for equality. 1135 * 1136 * Params: 1137 * R = Right hand side type. 1138 * that = Right hand side array range. 1139 * 1140 * Returns: $(D_KEYWORD true) if the array and the range are equal, 1141 * $(D_KEYWORD false) otherwise. 1142 */ 1143 bool opEquals(R)(R that) const 1144 if (is(R == Range) || is(R == ConstRange)) 1145 { 1146 return equal(opIndex(), that); 1147 } 1148 1149 /// 1150 @nogc nothrow pure @safe unittest 1151 { 1152 Array!int v1, v2; 1153 assert(v1 == v2); 1154 1155 v1.length = 1; 1156 v2.length = 2; 1157 assert(v1 != v2); 1158 1159 v1.length = 2; 1160 v1[0] = v2[0] = 2; 1161 v1[1] = 3; 1162 v2[1] = 4; 1163 assert(v1 != v2); 1164 1165 v2[1] = 3; 1166 assert(v1 == v2); 1167 } 1168 1169 /** 1170 * Returns: The first element. 1171 * 1172 * Precondition: $(D_INLINECODE !empty). 1173 */ 1174 @property ref inout(T) front() inout 1175 in 1176 { 1177 assert(!empty); 1178 } 1179 do 1180 { 1181 return *this.data; 1182 } 1183 1184 /// 1185 @nogc nothrow pure @safe unittest 1186 { 1187 auto v = Array!int([5]); 1188 1189 assert(v.front == 5); 1190 1191 v.length = 2; 1192 v[1] = 15; 1193 assert(v.front == 5); 1194 } 1195 1196 /** 1197 * Returns: The last element. 1198 * 1199 * Precondition: $(D_INLINECODE !empty). 1200 */ 1201 @property ref inout(T) back() inout @trusted 1202 in 1203 { 1204 assert(!empty); 1205 } 1206 do 1207 { 1208 return *(this.data + length - 1); 1209 } 1210 1211 /// 1212 @nogc nothrow pure @safe unittest 1213 { 1214 auto v = Array!int([5]); 1215 1216 assert(v.back == 5); 1217 1218 v.length = 2; 1219 v[1] = 15; 1220 assert(v.back == 15); 1221 } 1222 1223 /** 1224 * Params: 1225 * i = Slice start. 1226 * j = Slice end. 1227 * 1228 * Returns: A range that iterates over elements of the container from 1229 * index $(D_PARAM i) up to (excluding) index $(D_PARAM j). 1230 * 1231 * Precondition: $(D_INLINECODE i <= j && j <= length). 1232 */ 1233 Range opSlice(size_t i, size_t j) @trusted 1234 in 1235 { 1236 assert(i <= j); 1237 assert(j <= length); 1238 } 1239 do 1240 { 1241 return typeof(return)(this, this.data + i, this.data + j); 1242 } 1243 1244 /// ditto 1245 ConstRange opSlice(size_t i, size_t j) const @trusted 1246 in 1247 { 1248 assert(i <= j); 1249 assert(j <= length); 1250 } 1251 do 1252 { 1253 return typeof(return)(this, this.data + i, this.data + j); 1254 } 1255 1256 /// 1257 @nogc nothrow pure @safe unittest 1258 { 1259 auto v = Array!int([1, 2, 3]); 1260 auto r = v[]; 1261 1262 assert(r.front == 1); 1263 assert(r.back == 3); 1264 1265 r.popFront(); 1266 assert(r.front == 2); 1267 1268 r.popBack(); 1269 assert(r.back == 2); 1270 1271 assert(r.length == 1); 1272 } 1273 1274 /// 1275 @nogc nothrow pure @safe unittest 1276 { 1277 auto v = Array!int([1, 2, 3, 4]); 1278 auto r = v[1 .. 4]; 1279 assert(r.length == 3); 1280 assert(r[0] == 2); 1281 assert(r[1] == 3); 1282 assert(r[2] == 4); 1283 1284 r = v[0 .. 0]; 1285 assert(r.length == 0); 1286 1287 r = v[4 .. 4]; 1288 assert(r.length == 0); 1289 } 1290 1291 /** 1292 * Slicing assignment. 1293 * 1294 * Params: 1295 * R = Type of the assigned slice or length of the static array should 1296 * be assigned. 1297 * value = New value (single value, range or static array). 1298 * i = Slice start. 1299 * j = Slice end. 1300 * 1301 * Returns: Slice with the assigned part of the array. 1302 * 1303 * Precondition: $(D_INLINECODE i <= j && j <= length 1304 * && value.length == j - i) 1305 */ 1306 Range opSliceAssign(size_t R)(T[R] value, size_t i, size_t j) 1307 @trusted 1308 in 1309 { 1310 assert(i <= j); 1311 assert(j <= length); 1312 } 1313 do 1314 { 1315 copy(value[], this.data[i .. j]); 1316 return opSlice(i, j); 1317 } 1318 1319 /// ditto 1320 Range opSliceAssign(R : T)(auto ref R value, size_t i, size_t j) 1321 @trusted 1322 in 1323 { 1324 assert(i <= j); 1325 assert(j <= length); 1326 } 1327 do 1328 { 1329 fill(this.data[i .. j], value); 1330 return opSlice(i, j); 1331 } 1332 1333 /// ditto 1334 Range opSliceAssign()(Range value, size_t i, size_t j) @trusted 1335 in 1336 { 1337 assert(i <= j); 1338 assert(j <= length); 1339 assert(j - i == value.length); 1340 } 1341 do 1342 { 1343 copy(value, this.data[i .. j]); 1344 return opSlice(i, j); 1345 } 1346 1347 /// 1348 @nogc nothrow pure @safe unittest 1349 { 1350 auto v1 = Array!int([3, 3, 3]); 1351 auto v2 = Array!int([1, 2]); 1352 1353 v1[0 .. 2] = 286; 1354 assert(v1[0] == 286); 1355 assert(v1[1] == 286); 1356 assert(v1[2] == 3); 1357 1358 v2[0 .. $] = v1[1 .. 3]; 1359 assert(v2[0] == 286); 1360 assert(v2[1] == 3); 1361 1362 v1[0 .. 2] = [5, 8]; 1363 assert(v1[0] == 5); 1364 assert(v1[1] == 8); 1365 assert(v1[2] == 3); 1366 } 1367 1368 /** 1369 * Returns an array used internally by the array to store its owned elements. 1370 * The length of the returned array may differ from the size of the allocated 1371 * memory for the array: the array contains only initialized elements, but 1372 * not the reserved memory. 1373 * 1374 * Returns: The array with elements of this array. 1375 */ 1376 inout(T[]) get() inout 1377 { 1378 return this.data[0 .. length]; 1379 } 1380 1381 /// 1382 @nogc nothrow pure @system unittest 1383 { 1384 auto v = Array!int([1, 2, 4]); 1385 auto data = v.get(); 1386 1387 assert(data[0] == 1); 1388 assert(data[1] == 2); 1389 assert(data[2] == 4); 1390 assert(data.length == 3); 1391 1392 data = v[1 .. 2].get(); 1393 assert(data[0] == 2); 1394 assert(data.length == 1); 1395 } 1396 1397 /** 1398 * Assigns another array. 1399 * 1400 * If $(D_PARAM that) is passed by value, it won't be copied, but moved. 1401 * This array will take the ownership over $(D_PARAM that)'s storage and 1402 * the allocator. 1403 * 1404 * If $(D_PARAM that) is passed by reference, it will be copied. 1405 * 1406 * Params: 1407 * R = Content type. 1408 * that = The value should be assigned. 1409 * 1410 * Returns: $(D_KEYWORD this). 1411 */ 1412 ref typeof(this) opAssign(R)(ref R that) 1413 if (is(Unqual!R == Array)) 1414 { 1415 return this = that[]; 1416 } 1417 1418 /// ditto 1419 ref typeof(this) opAssign(R)(R that) 1420 if (is(R == Array)) 1421 { 1422 swap(this.data, that.data); 1423 swap(this.length_, that.length_); 1424 swap(this.capacity_, that.capacity_); 1425 swap(this.allocator_, that.allocator_); 1426 return this; 1427 } 1428 1429 /** 1430 * Assigns a range to the array. 1431 * 1432 * Params: 1433 * R = Content type. 1434 * that = The value should be assigned. 1435 * 1436 * Returns: $(D_KEYWORD this). 1437 */ 1438 ref typeof(this) opAssign(R)(scope R that) 1439 if (!isInfinite!R 1440 && isInputRange!R 1441 && isImplicitlyConvertible!(ElementType!R, T)) 1442 { 1443 length = 0; 1444 insertBack(that); 1445 return this; 1446 } 1447 1448 /// 1449 @nogc nothrow pure @safe unittest 1450 { 1451 auto v1 = const Array!int([5, 15, 8]); 1452 Array!int v2; 1453 v2 = v1; 1454 assert(v1 == v2); 1455 } 1456 1457 /** 1458 * Assigns a static array. 1459 * 1460 * Params: 1461 * R = Static array size. 1462 * that = Values to initialize the array with. 1463 * 1464 * Returns: $(D_KEYWORD this). 1465 */ 1466 ref typeof(this) opAssign(size_t R)(T[R] that) 1467 { 1468 return opAssign!(T[])(that[]); 1469 } 1470 1471 /// 1472 @nogc nothrow pure @safe unittest 1473 { 1474 auto v1 = Array!int([5, 15, 8]); 1475 Array!int v2; 1476 1477 v2 = [5, 15, 8]; 1478 assert(v1 == v2); 1479 } 1480 1481 mixin DefaultAllocator; 1482 } 1483 1484 /// 1485 @nogc nothrow pure @safe unittest 1486 { 1487 auto v = Array!int([5, 15, 8]); 1488 1489 assert(v.front == 5); 1490 assert(v[1] == 15); 1491 assert(v.back == 8); 1492 1493 auto r = v[]; 1494 r[0] = 7; 1495 assert(r.front == 7); 1496 assert(r.front == v.front); 1497 }