1 module fixedsizearray; 2 3 import std.array : back; 4 import std.experimental.logger; 5 6 struct FixedSizeArraySlice(FSA,T, size_t Size) { 7 FSA* fsa; 8 short low; 9 short high; 10 11 pragma(inline, true) 12 this(FSA* fsa, short low, short high) { 13 this.fsa = fsa; 14 this.low = low; 15 this.high = high; 16 } 17 18 pragma(inline, true) 19 @property bool empty() const pure @safe nothrow @nogc { 20 return this.low >= this.high; 21 } 22 23 pragma(inline, true) 24 @property size_t length() pure @safe nothrow @nogc { 25 return cast(size_t)(this.high - this.low); 26 } 27 28 pragma(inline, true) 29 @property ref T front() { 30 return (*this.fsa)[cast(size_t)this.low]; 31 } 32 33 pragma(inline, true) 34 @property ref const(T) front() const { 35 return (*this.fsa)[cast(size_t)this.low]; 36 } 37 38 pragma(inline, true) 39 @property ref T back() { 40 return (*this.fsa)[cast(size_t)(this.high - 1)]; 41 } 42 43 pragma(inline, true) 44 @property ref const(T) back() const { 45 return (*this.fsa)[cast(size_t)(this.high - 1)]; 46 } 47 48 pragma(inline, true) 49 void insertBack(S)(auto ref S s) { 50 (*this.fsa).insertBack(s); 51 } 52 53 /// Ditto 54 alias put = insertBack; 55 56 pragma(inline, true) 57 ref T opIndex(const size_t idx) { 58 return (*this.fsa)[this.low + idx]; 59 } 60 61 pragma(inline, true) 62 void popFront() pure @safe nothrow @nogc { 63 ++this.low; 64 } 65 66 pragma(inline, true) 67 void popBack() pure @safe nothrow @nogc { 68 --this.high; 69 } 70 71 pragma(inline, true) 72 @property typeof(this) save() pure @safe nothrow @nogc { 73 return this; 74 } 75 76 pragma(inline, true) 77 @property const(typeof(this)) save() const pure @safe nothrow @nogc { 78 return this; 79 } 80 81 pragma(inline, true) 82 typeof(this) opIndex() pure @safe nothrow @nogc { 83 return this; 84 } 85 86 pragma(inline, true) 87 typeof(this) opIndex(size_t l, size_t h) pure @safe nothrow @nogc { 88 return this.opSlice(l, h); 89 } 90 91 pragma(inline, true) 92 typeof(this) opSlice(size_t l, size_t h) pure @safe nothrow @nogc { 93 assert(l <= h); 94 return typeof(this)(this.fsa, 95 cast(short)(this.low + l), 96 cast(short)(this.low + h) 97 ); 98 } 99 } 100 101 struct FixedSizeArray(T,size_t Size = 32) { 102 import std.traits; 103 enum ByteCap = T.sizeof * Size; 104 align(8) void[ByteCap] store; 105 long base; 106 long length_; 107 108 /** If `true` no destructor of any element stored in the FixedSizeArray 109 will be called. 110 */ 111 bool disableDtor; 112 113 pragma(inline, true) 114 this(Args...)(Args args) { 115 foreach(it; args) { 116 static if(isAssignable!(T,typeof(it))) { 117 this.insertBack(it); 118 } 119 } 120 } 121 122 pragma(inline, true) 123 ~this() { 124 static if(hasElaborateDestructor!T) { 125 if(!this.disableDtor) { 126 this.removeAll(); 127 } 128 } 129 } 130 131 pragma(inline, true) 132 size_t capacity() const @nogc @safe pure nothrow { 133 return Size; 134 } 135 136 /** This function inserts an `S` element at the back if there is space. 137 Otherwise the behaviour is undefined. 138 */ 139 pragma(inline, true) 140 void insertBack(S)(auto ref S t) @trusted if(is(Unqual!(S) == T)) { 141 import std.conv : emplace; 142 assert(this.length + 1 <= Size); 143 144 *(cast(T*)(&this.store[ 145 cast(size_t)((this.base + this.length_) % ByteCap) 146 ])) = t; 147 this.length_ += T.sizeof; 148 } 149 150 /// Ditto 151 pragma(inline, true) 152 void insertBack(S)(auto ref S s) @trusted if(!is(Unqual!(S) == T)) { 153 import std.traits; 154 import std.conv; 155 156 static if((isIntegral!T || isFloatingPoint!T) 157 || (isSomeChar!T && isSomeChar!S && T.sizeof >= S.sizeof)) 158 { 159 this.insertBack!T(cast(T)(s)); 160 } else static if (isSomeChar!T && isSomeChar!S && T.sizeof < S.sizeof) { 161 /* may throwable operation: 162 * - std.utf.encode 163 */ 164 // must do some transcoding around here 165 import std.utf : encode; 166 Unqual!T[T.sizeof == 1 ? 4 : 2] encoded; 167 auto len = encode(encoded, s); 168 foreach(T it; encoded[0 .. len]) { 169 this.insertBack!T(it); 170 } 171 } else static if(isAssignable!(T,S)) { 172 *(cast(T*)(&this.store[ 173 cast(size_t)((this.base + this.length_) % ByteCap) 174 ])) = s; 175 this.length_ += T.sizeof; 176 } else { 177 static assert(false); 178 } 179 } 180 181 /// Ditto 182 pragma(inline, true) 183 void insertBack(S)(auto ref S defaultValue, size_t num) { 184 for(size_t i = 0; i < num; ++i) { 185 this.insertBack(defaultValue); 186 } 187 } 188 189 /// 190 pure @safe unittest { 191 FixedSizeArray!(int,32) fsa; 192 fsa.insertBack(1337); 193 assert(fsa.length == 1); 194 assert(fsa[0] == 1337); 195 196 fsa.insertBack(99, 5); 197 198 foreach(it; fsa[1 .. fsa.length]) { 199 assert(it == 99); 200 } 201 } 202 203 /** This function inserts an `S` element at the front if there is space. 204 Otherwise the behaviour is undefined. 205 */ 206 pragma(inline, true) 207 void insertFront(S)(auto ref S t) @trusted if(is(Unqual!(S) == T)) { 208 import std.conv : emplace; 209 import std.stdio; 210 assert(this.length + 1 <= Size); 211 212 this.base -= T.sizeof; 213 if(this.base < 0) { 214 this.base = cast(typeof(this.base))((ByteCap) - T.sizeof); 215 } 216 217 *(cast(T*)(&this.store[cast(size_t)this.base])) = t; 218 this.length_ += T.sizeof; 219 } 220 221 pure @safe unittest { 222 FixedSizeArray!(int,32) fsa; 223 fsa.insertFront(1337); 224 assert(fsa.length == 1); 225 assert(fsa[0] == 1337); 226 assert(fsa.front == 1337); 227 assert(fsa.back == 1337); 228 229 fsa.removeBack(); 230 assert(fsa.length == 0); 231 assert(fsa.empty); 232 fsa.insertFront(1336); 233 234 assert(fsa.length == 1); 235 assert(fsa[0] == 1336); 236 assert(fsa.front == 1336); 237 assert(fsa.back == 1336); 238 } 239 240 pure @safe unittest { 241 FixedSizeArray!(int,16) fsa; 242 for(int i = 0; i < 32; ++i) { 243 fsa.insertFront(i); 244 assert(fsa.length == 1); 245 assert(!fsa.empty); 246 assert(fsa.front == i); 247 assert(fsa.back == i); 248 fsa.removeFront(); 249 assert(fsa.length == 0); 250 assert(fsa.empty); 251 } 252 } 253 254 pure @safe unittest { 255 FixedSizeArray!(int,16) fsa; 256 for(int i = 0; i < 32; ++i) { 257 fsa.insertFront(i); 258 assert(fsa.length == 1); 259 assert(!fsa.empty); 260 assert(fsa.front == i); 261 assert(fsa.back == i); 262 fsa.removeBack(); 263 assert(fsa.length == 0); 264 assert(fsa.empty); 265 } 266 } 267 268 pure @safe nothrow unittest { 269 FixedSizeArray!(int,16) fsa; 270 for(int i = 0; i < 32; ++i) { 271 fsa.insertBack(i); 272 assert(fsa.length == 1); 273 assert(!fsa.empty); 274 assert(fsa.front == i); 275 assert(fsa.back == i); 276 fsa.removeFront(); 277 assert(fsa.length == 0); 278 assert(fsa.empty); 279 } 280 } 281 282 /** This function emplaces an `S` element at the back if there is space. 283 Otherwise the behaviour is undefined. 284 */ 285 pragma(inline, true) 286 void emplaceBack(Args...)(auto ref Args args) { 287 import std.conv : emplace; 288 assert(this.length + 1 <= Size); 289 290 emplace(cast(T*)(&this.store[ 291 cast(size_t)((this.base + this.length_) % ByteCap)] 292 ), args); 293 this.length_ += T.sizeof; 294 } 295 296 /** This function removes an element form the back of the array. 297 */ 298 pragma(inline, true) 299 void removeBack() { 300 assert(!this.empty); 301 302 static if(hasElaborateDestructor!T) { 303 if(!this.disableDtor) { 304 static if(hasMember!(T, "__dtor")) { 305 this.back().__dtor(); 306 } else static if(hasMember!(T, "__xdtor")) { 307 this.back().__xdtor(); 308 } else { 309 static assert(false); 310 } 311 } 312 } 313 314 this.length_ -= T.sizeof; 315 } 316 317 /** This function removes an element form the front of the array. 318 */ 319 pragma(inline, true) 320 void removeFront() { 321 assert(!this.empty); 322 323 static if(hasElaborateDestructor!T) { 324 if(!this.disableDtor) { 325 static if(hasMember!(T, "__dtor")) { 326 this.back().__dtor(); 327 } else static if(hasMember!(T, "__xdtor")) { 328 this.back().__xdtor(); 329 } else { 330 static assert(false); 331 } 332 } 333 } 334 335 //this.begin = (this.begin + T.sizeof) % (Size * T.sizeof); 336 this.base += T.sizeof; 337 if(this.base >= ByteCap) { 338 this.base = 0; 339 } 340 this.length_ -= T.sizeof; 341 } 342 343 pure @safe unittest { 344 FixedSizeArray!(int,32) fsa; 345 fsa.insertBack(1337); 346 assert(fsa.length == 1); 347 assert(fsa[0] == 1337); 348 349 fsa.removeBack(); 350 assert(fsa.length == 0); 351 assert(fsa.empty); 352 } 353 354 /** This function removes all elements from the array. 355 */ 356 pragma(inline, true) 357 void removeAll() { 358 while(!this.empty) { 359 this.removeBack(); 360 } 361 } 362 363 pure @safe unittest { 364 FixedSizeArray!(int,32) fsa; 365 fsa.insertBack(1337); 366 fsa.insertBack(1338); 367 assert(fsa.length == 2); 368 assert(fsa[0] == 1337); 369 assert(fsa[1] == 1338); 370 371 fsa.removeAll(); 372 assert(fsa.length == 0); 373 assert(fsa.empty); 374 } 375 376 pragma(inline, true) 377 void remove(ulong idx) { 378 import std.stdio; 379 if(idx == 0) { 380 this.removeFront(); 381 } else if(idx == this.length - 1) { 382 this.removeBack(); 383 } else { 384 for(long i = idx + 1; i < this.length; ++i) { 385 this[cast(size_t)(i - 1)] = this[cast(size_t)i]; 386 } 387 this.removeBack(); 388 } 389 } 390 391 unittest { 392 FixedSizeArray!(int,16) fsa; 393 foreach(i; 0..10) { 394 fsa.insertBack(i); 395 } 396 fsa.remove(1); 397 foreach(idx, i; [0,2,3,4,5,6,7,8,9]) { 398 assert(fsa[idx] == i); 399 } 400 fsa.remove(0); 401 foreach(idx, i; [2,3,4,5,6,7,8,9]) { 402 assert(fsa[idx] == i); 403 } 404 fsa.remove(7); 405 foreach(idx, i; [2,3,4,5,6,7,8]) { 406 assert(fsa[idx] == i); 407 } 408 fsa.remove(5); 409 foreach(idx, i; [2,3,4,5,6,8]) { 410 assert(fsa[idx] == i); 411 } 412 fsa.remove(1); 413 foreach(idx, i; [2,4,5,6,8]) { 414 assert(fsa[idx] == i); 415 } 416 fsa.remove(0); 417 foreach(idx, i; [4,5,6,8]) { 418 assert(fsa[idx] == i); 419 } 420 fsa.remove(0); 421 foreach(idx, i; [5,6,8]) { 422 assert(fsa[idx] == i); 423 } 424 } 425 426 /** Access the last or the first element of the array. 427 */ 428 pragma(inline, true) 429 @property ref T back() @trusted { 430 assert(!this.empty); 431 return *(cast(T*)(&this.store[ 432 cast(size_t)(this.base + this.length_ - T.sizeof) % ByteCap 433 ])); 434 } 435 436 pragma(inline, true) 437 @property ref const(T) back() const @trusted { 438 assert(!this.empty); 439 return *(cast(T*)(&this.store[ 440 cast(size_t)(this.base + this.length_ - T.sizeof) % ByteCap 441 ])); 442 } 443 444 /// Ditto 445 pragma(inline, true) 446 @property ref T front() @trusted { 447 assert(!this.empty); 448 return *(cast(T*)(&this.store[cast(size_t)this.base])); 449 } 450 451 pragma(inline, true) 452 @property ref const(T) front() const @trusted { 453 assert(!this.empty); 454 return *(cast(T*)(&this.store[cast(size_t)this.base])); 455 } 456 457 /// 458 pure @safe unittest { 459 FixedSizeArray!(int,32) fsa; 460 fsa.insertBack(1337); 461 fsa.insertBack(1338); 462 assert(fsa.length == 2); 463 464 assert(fsa.front == 1337); 465 assert(fsa.back == 1338); 466 } 467 468 /** Use an index to access the array. 469 */ 470 pragma(inline, true) 471 ref T opIndex(const size_t idx) @trusted { 472 import std.format : format; 473 assert(idx <= this.length, format("%s %s", idx, this.length)); 474 return *(cast(T*)(&this.store[ 475 cast(size_t)((this.base + idx * T.sizeof) % ByteCap) 476 ])); 477 } 478 479 /// Ditto 480 pragma(inline, true) 481 ref const(T) opIndex(const size_t idx) @trusted const { 482 import std.format : format; 483 assert(idx <= this.length, format("%s %s", idx, this.length)); 484 return *(cast(const(T)*)(&this.store[ 485 cast(size_t)((this.base + idx * T.sizeof) % ByteCap) 486 ])); 487 } 488 489 /// 490 pure @safe unittest { 491 FixedSizeArray!(int,32) fsa; 492 fsa.insertBack(1337); 493 fsa.insertBack(1338); 494 assert(fsa.length == 2); 495 496 assert(fsa[0] == 1337); 497 assert(fsa[1] == 1338); 498 } 499 500 /// Gives the length of the array. 501 pragma(inline, true) 502 @property size_t length() const pure @nogc nothrow { 503 return cast(size_t)(this.length_ / T.sizeof); 504 } 505 506 /// Ditto 507 pragma(inline, true) 508 @property bool empty() const pure @nogc nothrow { 509 return this.length == 0; 510 } 511 512 /// 513 pure @safe nothrow unittest { 514 FixedSizeArray!(int,32) fsa; 515 assert(fsa.empty); 516 assert(fsa.length == 0); 517 518 fsa.insertBack(1337); 519 fsa.insertBack(1338); 520 521 assert(fsa.length == 2); 522 assert(!fsa.empty); 523 } 524 525 pragma(inline, true) 526 FixedSizeArraySlice!(typeof(this),T,Size) opSlice() pure @nogc @safe nothrow { 527 return FixedSizeArraySlice!(typeof(this),T,Size)(&this, cast(short)0, 528 cast(short)this.length 529 ); 530 } 531 532 pragma(inline, true) 533 FixedSizeArraySlice!(typeof(this),T,Size) opSlice(const size_t low, 534 const size_t high) 535 pure @nogc @safe nothrow 536 { 537 return FixedSizeArraySlice!(typeof(this),T,Size)(&this, cast(short)low, 538 cast(short)high 539 ); 540 } 541 542 pragma(inline, true) 543 auto opSlice() pure @nogc @safe nothrow const { 544 return FixedSizeArraySlice!(typeof(this),const(T),Size) 545 (&this, cast(short)0, cast(short)this.length); 546 } 547 548 pragma(inline, true) 549 auto opSlice(const size_t low, const size_t high) pure @nogc @safe nothrow const 550 { 551 return FixedSizeArraySlice!(typeof(this),const(T),Size) 552 (&this, cast(short)low, cast(short)high); 553 } 554 } 555 556 unittest { 557 FixedSizeArray!(int, 10) fsa; 558 assert(fsa.empty); 559 560 fsa.insertBack(1); 561 assert(fsa.front == 1); 562 assert(fsa.back == 1); 563 assert(fsa[0] == 1); 564 565 fsa.insertFront(0); 566 assert(fsa.front == 0); 567 assert(fsa.back == 1); 568 assert(fsa[0] == 0); 569 assert(fsa[1] == 1); 570 571 int idx = 0; 572 foreach(it; fsa[0 .. fsa.length]) { 573 assert(it == idx); 574 ++idx; 575 } 576 577 fsa.removeFront(); 578 assert(fsa.front == 1); 579 assert(fsa.back == 1); 580 assert(fsa[0] == 1); 581 582 fsa.removeBack(); 583 assert(fsa.empty); 584 } 585 unittest { 586 import exceptionhandling; 587 import std.stdio; 588 589 FixedSizeArray!(int, 16) fsa; 590 assert(fsa.empty); 591 cast(void)assertEqual(fsa.length, 0); 592 593 fsa.insertBack(1); 594 assert(!fsa.empty); 595 cast(void)assertEqual(fsa.length, 1); 596 cast(void)assertEqual(fsa.front, 1); 597 cast(void)assertEqual(fsa.back, 1); 598 599 fsa.insertBack(2); 600 assert(!fsa.empty); 601 cast(void)assertEqual(fsa.length, 2); 602 cast(void)assertEqual(fsa.front, 1); 603 cast(void)assertEqual(fsa.back, 2); 604 605 fsa.removeFront(); 606 assert(!fsa.empty); 607 cast(void)assertEqual(fsa.length, 1); 608 cast(void)assertEqual(fsa.front, 2); 609 cast(void)assertEqual(fsa.back, 2); 610 611 fsa.removeBack(); 612 //writefln("%s %s", fsa.begin, fsa.end); 613 assert(fsa.empty); 614 cast(void)assertEqual(fsa.length, 0); 615 } 616 617 unittest { 618 import std.format; 619 620 FixedSizeArray!(char,64) fsa; 621 formattedWrite(fsa[], "%s %s %s", "Hello", "World", 42); 622 //assert(cast(string)fsa == "Hello World 42", cast(string)fsa); 623 } 624 625 unittest { 626 import exceptionhandling; 627 628 FixedSizeArray!(int,16) fsa; 629 auto a = [0,1,2,4,32,64,1024,2048,65000]; 630 foreach(idx, it; a) { 631 fsa.insertBack(it); 632 assertEqual(fsa.length, idx + 1); 633 assertEqual(fsa.back, it); 634 for(int i = 0; i < idx; ++i) { 635 assertEqual(fsa[i], a[i]); 636 } 637 } 638 } 639 640 unittest { 641 import exceptionhandling; 642 import std.traits; 643 import std.meta; 644 import std.range; 645 import std.stdio; 646 foreach(Type; AliasSeq!(byte,int,long)) { 647 FixedSizeArray!(Type,16) fsa2; 648 static assert(isInputRange!(typeof(fsa2[]))); 649 static assert(isForwardRange!(typeof(fsa2[]))); 650 static assert(isBidirectionalRange!(typeof(fsa2[]))); 651 foreach(idx, it; [[0], [0,1,2,3,4], [2,3,6,5,6,21,9,36,61,62]]) { 652 FixedSizeArray!(Type,16) fsa; 653 foreach(jdx, jt; it) { 654 fsa.insertBack(jt); 655 //writefln("%s idx %d jdx %d length %d", Type.stringof, idx, jdx, fsa.length); 656 cast(void)assertEqual(fsa.length, jdx + 1); 657 foreach(kdx, kt; it[0 .. jdx]) { 658 assertEqual(fsa[kdx], kt); 659 } 660 661 { 662 auto forward = fsa[]; 663 auto forward2 = forward; 664 cast(void)assertEqual(forward.length, jdx + 1); 665 for(size_t i = 0; i < forward.length; ++i) { 666 cast(void)assertEqual(forward[i], it[i]); 667 cast(void)assertEqual(forward2.front, it[i]); 668 forward2.popFront(); 669 } 670 assert(forward2.empty); 671 672 auto backward = fsa[]; 673 auto backward2 = backward.save; 674 cast(void)assertEqual(backward.length, jdx + 1); 675 for(size_t i = 0; i < backward.length; ++i) { 676 cast(void)assertEqual(backward[backward.length - i - 1], 677 it[jdx - i] 678 ); 679 680 cast(void)assertEqual(backward2.back, 681 it[0 .. jdx + 1 - i].back 682 ); 683 backward2.popBack(); 684 } 685 assert(backward2.empty); 686 auto forward3 = fsa[].save; 687 auto forward4 = fsa[0 .. jdx + 1]; 688 689 while(!forward3.empty && !forward4.empty) { 690 cast(void)assertEqual(forward3.front, forward4.front); 691 cast(void)assertEqual(forward3.back, forward4.back); 692 forward3.popFront(); 693 forward4.popFront(); 694 } 695 assert(forward3.empty); 696 assert(forward4.empty); 697 } 698 699 { 700 const(FixedSizeArray!(Type,16))* constFsa; 701 constFsa = &fsa; 702 auto forward = (*constFsa)[]; 703 auto forward2 = forward.save; 704 cast(void)assertEqual(forward.length, jdx + 1); 705 for(size_t i = 0; i < forward.length; ++i) { 706 cast(void)assertEqual(cast(int)forward[i], it[i]); 707 cast(void)assertEqual(cast(int)forward2.front, it[i]); 708 forward2.popFront(); 709 } 710 assert(forward2.empty); 711 712 auto backward = (*constFsa)[]; 713 auto backward2 = backward.save; 714 cast(void)assertEqual(backward.length, jdx + 1); 715 for(size_t i = 0; i < backward.length; ++i) { 716 cast(void)assertEqual(backward[backward.length - i - 1], 717 it[jdx - i] 718 ); 719 720 cast(void)assertEqual(backward2.back, 721 it[0 .. jdx + 1 - i].back 722 ); 723 backward2.popBack(); 724 } 725 assert(backward2.empty); 726 auto forward3 = (*constFsa)[]; 727 auto forward4 = (*constFsa)[0 .. jdx + 1]; 728 729 while(!forward3.empty && !forward4.empty) { 730 cast(void)assertEqual(forward3.front, forward4.front); 731 cast(void)assertEqual(forward3.back, forward4.back); 732 forward3.popFront(); 733 forward4.popFront(); 734 } 735 assert(forward3.empty); 736 assert(forward4.empty); 737 } 738 } 739 } 740 } 741 } 742 743 unittest { 744 import exceptionhandling; 745 746 int cnt; 747 int cnt2; 748 749 struct Foo { 750 int* cnt; 751 this(int* cnt) { this.cnt = cnt; } 752 ~this() { if(cnt) { ++(*cnt); } } 753 } 754 755 int i = 0; 756 for(; i < 1000; ++i) { 757 { 758 FixedSizeArray!(Foo) fsa; 759 fsa.insertBack(Foo(&cnt)); 760 fsa.insertBack(Foo(&cnt)); 761 fsa.insertBack(Foo(&cnt)); 762 fsa.insertBack(Foo(&cnt)); 763 } 764 765 cast(void)assertEqual(cnt, 8 * i + 8); 766 767 { 768 FixedSizeArray!(Foo) fsa; 769 fsa.emplaceBack(&cnt2); 770 fsa.emplaceBack(&cnt2); 771 fsa.emplaceBack(&cnt2); 772 fsa.emplaceBack(&cnt2); 773 } 774 cast(void)assertEqual(cnt2, 4 * i + 4); 775 } 776 } 777 778 // Test case Issue #2 779 unittest { 780 import exceptionhandling; 781 782 FixedSizeArray!(int,2) fsa; 783 fsa.insertBack(0); 784 fsa.insertBack(1); 785 786 assertEqual(fsa[0], 0); 787 assertEqual(fsa[1], 1); 788 assertEqual(fsa.front, 0); 789 assertEqual(fsa.back, 1); 790 } 791 792 unittest { 793 import exceptionhandling; 794 import std.stdio; 795 string s = "Hellö Wärlß"; 796 { 797 FixedSizeArray!(char,32) fsa; 798 foreach(dchar c; s) { 799 fsa.insertBack(c); 800 } 801 for(int i = 0; i < s.length; ++i) { 802 assert(fsa[i] == s[i]); 803 } 804 } 805 { 806 import std.format; 807 FixedSizeArray!(char,32) fsa; 808 formattedWrite(fsa[], s); 809 for(int i = 0; i < s.length; ++i) { 810 assert(fsa[i] == s[i]); 811 } 812 } 813 } 814 815 unittest { 816 import std.stdio; 817 import core.memory; 818 enum size = 128; 819 auto arrays = new FixedSizeArray!(int, size)[size]; 820 GC.removeRoot(arrays.ptr); 821 //FixedSizeArray!(int, size)[size] arrays; 822 foreach (i; 0..size) { 823 foreach (j; 0..size) { 824 assert(arrays[i].length == j); 825 arrays[i].insertBack(i * 1000 + j); 826 } 827 } 828 /*foreach(ref it; arrays) { 829 writef("%d ", it.length); 830 } 831 writeln();*/ 832 bool[int] o; 833 foreach (i; 0..size) { 834 foreach (j; 0..size) { 835 assert(arrays[i][j] !in o); 836 o[arrays[i][j]] = true; 837 } 838 } 839 assert(size * size == o.length); 840 } 841 842 // issue #1 won't fix not sure why 843 unittest { 844 import std.stdio; 845 import core.memory; 846 enum size = 256; 847 auto arrays = new FixedSizeArray!(Object,size)(); 848 //FixedSizeArray!(Object, size) arrays; 849 foreach (i; 0..size) { 850 auto o = new Object(); 851 assert(arrays.length == i); 852 foreach(it; (*arrays)[]) { 853 assert(it !is null); 854 assert(it.toHash()); 855 } 856 arrays.insertBack(o); 857 assert(arrays.back is o); 858 assert(!arrays.empty); 859 assert(arrays.length == i + 1); 860 } 861 862 assert(arrays.length == size); 863 for(int i = 0; i < size; ++i) { 864 assert((*arrays)[i] !is null); 865 assert((*arrays)[i].toHash()); 866 } 867 bool[Object] o; 868 foreach (i; 0..size) { 869 assert((*arrays)[i] !is null); 870 assert((*arrays)[i] !in o); 871 o[(*arrays)[i]] = true; 872 873 } 874 assert(size == o.length); 875 } 876 877 unittest { 878 import exceptionhandling; 879 FixedSizeArray!(int,16) fsa; 880 fsa.insertFront(1337); 881 assert(!fsa.empty); 882 assertEqual(fsa.length, 1); 883 assertEqual(fsa.back, 1337); 884 assertEqual(fsa.front, 1337); 885 assertEqual(fsa.base, 15 * int.sizeof); 886 } 887 888 // Test case Issue #2 889 unittest { 890 enum size = 256; 891 auto arrays = new FixedSizeArray!(Object, size * Object.sizeof)[size]; 892 foreach (i; 0..size) { 893 foreach (j; 0..size) { 894 arrays[i].insertBack(new Object); 895 } 896 } 897 bool[Object] o; 898 foreach (i; 0..size) { 899 foreach (j; 0..size) { 900 o[arrays[i][j]] = true; 901 } 902 } 903 assert(o.length == size * size); 904 } 905 906 unittest { 907 import exceptionhandling; 908 struct Foo { 909 int* a; 910 this(int* a) { 911 this.a = a; 912 } 913 ~this() { 914 if(this.a !is null) { 915 ++(*a); 916 } 917 } 918 } 919 920 { 921 int a = 0; 922 { 923 FixedSizeArray!(Foo,16) fsa; 924 for(int i = 0; i < 10; ++i) { 925 fsa.emplaceBack(&a); 926 } 927 } 928 assertEqual(a, 10); 929 } 930 { 931 int a = 0; 932 { 933 FixedSizeArray!(Foo,16) fsa; 934 fsa.disableDtor = true; 935 for(int i = 0; i < 10; ++i) { 936 fsa.emplaceBack(&a); 937 } 938 } 939 assertEqual(a, 0); 940 } 941 } 942 943 unittest { 944 import std.range.primitives : hasAssignableElements, hasSlicing, isRandomAccessRange; 945 FixedSizeArray!(int,32) fsa; 946 auto s = fsa[]; 947 static assert(hasSlicing!(typeof(s))); 948 static assert(isRandomAccessRange!(typeof(s))); 949 static assert(hasAssignableElements!(typeof(s))); 950 } 951 952 unittest { 953 import exceptionhandling; 954 955 FixedSizeArray!(int,32) fsa; 956 for(int i = 0; i < 32; ++i) { 957 fsa.insertBack(i); 958 } 959 960 auto s = fsa[]; 961 for(int i = 0; i < 32; ++i) { 962 assert(s[i] == i); 963 } 964 s = s[0 .. 33]; 965 for(int i = 0; i < 32; ++i) { 966 assert(s[i] == i); 967 } 968 969 auto t = s.save; 970 s.popFront(); 971 for(int i = 0; i < 32; ++i) { 972 assert(t[i] == i); 973 } 974 975 auto r = t[10, 20]; 976 for(int i = 10; i < 20; ++i) { 977 assertEqual(r[i-10], fsa[i]); 978 } 979 980 foreach(ref it; r) { 981 it = 0; 982 } 983 984 for(int i = 10; i < 20; ++i) { 985 assertEqual(r[i-10], 0); 986 } 987 } 988 989 unittest { 990 FixedSizeArray!(int,32) fsaM; 991 for(int i = 0; i < 32; ++i) { 992 fsaM.insertBack(i); 993 } 994 995 const(FixedSizeArray!(int,32)) fsa = fsaM; 996 997 auto s = fsa[]; 998 for(int i = 0; i < 32; ++i) { 999 assert(s[i] == i); 1000 } 1001 s = s[0 .. 33]; 1002 for(int i = 0; i < 32; ++i) { 1003 assert(s[i] == i); 1004 } 1005 1006 auto t = s.save; 1007 s.popFront(); 1008 for(int i = 0; i < 32; ++i) { 1009 assert(t[i] == i); 1010 } 1011 } 1012 1013 unittest { 1014 import std.random : Random, uniform; 1015 import std.format : format; 1016 struct Data { 1017 ulong a, b, c, d, e; 1018 } 1019 1020 auto rnd = Random(1337); 1021 FixedSizeArray!(Data,128) a; 1022 for(size_t i = 0; i < 4096; ++i) { 1023 Data d; 1024 d.a = i; 1025 d.b = i; 1026 d.c = i; 1027 d.d = i; 1028 d.e = i; 1029 1030 a.insertBack(d); 1031 1032 int c = uniform(4,10, rnd); 1033 while(a.length > c) { 1034 a.removeFront(); 1035 } 1036 assert(!a.empty); 1037 assert(a.length <= c, format("%d < %d", a.length, c)); 1038 1039 auto r = a[]; 1040 assert(r.back.a == i); 1041 assert(r.front.a <= i); 1042 1043 foreach(it; r[]) { 1044 assert(it.a <= i); 1045 } 1046 1047 auto cr = (*(cast(const(typeof(a))*)(&a))); 1048 assert(cr.back.a == i); 1049 assert(cr.front.a <= i); 1050 1051 auto crr = cr[]; 1052 assert(crr.front.a <= i); 1053 assert(crr.back.a <= i); 1054 foreach(it; crr.save) { 1055 assert(it.a <= i); 1056 } 1057 } 1058 }