1 module ut.vector; 2 3 4 import ut; 5 import automem.vector; 6 import std.experimental.allocator.mallocator: Mallocator; 7 import test_allocator; 8 9 10 @("length") 11 @safe unittest { 12 vector("foo", "bar", "baz").length.should == 3; 13 vector("quux", "toto").length.should == 2; 14 } 15 16 @("vector.int") 17 @safe unittest { 18 vector(1, 2, 3, 4, 5).range.should == [1, 2, 3, 4, 5]; 19 vector(2, 3, 4).range.should == [2, 3, 4]; 20 vector(2, 3, 4).range.should == [2, 3, 4]; 21 } 22 23 @("vector.double") 24 @safe unittest { 25 vector(33.3).range.should == [33.3]; 26 vector(22.2, 77.7).range.should == [22.2, 77.7]; 27 } 28 29 @("copying") 30 @safe unittest { 31 auto vec1 = vector(1, 2, 3); 32 () @trusted { vec1.reserve(10); }(); 33 auto vec2 = vec1; 34 vec1[1] = 7; 35 36 vec1.range.should == [1, 7, 3]; 37 vec2.range.should == [1, 2, 3]; 38 } 39 40 @("bounds check") 41 @safe unittest { 42 43 auto vec = vector(1, 2, 3); 44 () @trusted { vec.reserve(10); }(); 45 vec[3].shouldThrow!BoundsException; 46 vec[-1].shouldThrow!BoundsException; 47 () @trusted { vec[0 .. 4].shouldThrow!BoundsException; }(); 48 () @trusted { vec[0.. 3]; }(); // shouldn't throw (see #45) 49 } 50 51 @("extend") 52 @system unittest { 53 import std.algorithm: map; 54 55 auto vec = vector(0, 1, 2, 3); 56 57 vec ~= 4; 58 vec.range.should == [0, 1, 2, 3, 4]; 59 60 vec ~= [5, 6]; 61 vec.range.should == [0, 1, 2, 3, 4, 5, 6]; 62 63 vec ~= [1, 2].map!(a => a + 10); 64 vec.range.should == [0, 1, 2, 3, 4, 5, 6, 11, 12]; 65 } 66 67 68 @("put") 69 @system unittest { 70 import std.range: iota; 71 72 auto vec = vector(0, 1, 2, 3); 73 vec.put(4); 74 vec.range.should == [0, 1, 2, 3, 4]; 75 vec.put(2.iota); 76 vec.range.should == [0, 1, 2, 3, 4, 0, 1]; 77 } 78 79 @("append") 80 @system unittest { 81 auto vec1 = vector(0, 1, 2); 82 auto vec2 = vector(3, 4); 83 84 auto vec3 = vec1 ~ vec2; 85 vec3.range.should == [0, 1, 2, 3, 4]; 86 87 vec1[0] = 7; 88 vec2[0] = 9; 89 vec3.range.should == [0, 1, 2, 3, 4]; 90 91 92 // make sure capacity is larger 93 vec1 ~= 100; 94 vec1.capacity.shouldBeGreaterThan(vec1.length); 95 vec1.range.should == [7, 1, 2, 100]; 96 97 vec2 ~= 200; 98 vec2.capacity.shouldBeGreaterThan(vec2.length); 99 vec2.range.should == [9, 4, 200]; 100 101 (vec1 ~ vec2).range.should == [7, 1, 2, 100, 9, 4, 200]; 102 (vec1 ~ vector(11, 12, 13, 14, 15)).range.should == [7, 1, 2, 100, 11, 12, 13, 14, 15]; 103 } 104 105 @("slice") 106 @system unittest { 107 const vec = vector(0, 1, 2, 3, 4, 5); 108 vec[].should == [0, 1, 2, 3, 4, 5]; 109 vec[1 .. 3].should == [1, 2]; 110 vec[1 .. 4].should == [1, 2, 3]; 111 vec[2 .. 5].should == [2, 3, 4]; 112 vec[1 .. $ - 1].should == [1, 2, 3, 4]; 113 vec[0 .. 6].should == [0, 1, 2, 3, 4, 5]; 114 } 115 116 @("opDollar") 117 @system unittest { 118 auto vec = vector(0, 1, 2, 3, 4); 119 vec ~= 5; 120 vec ~= 6; 121 vec.capacity.shouldBeGreaterThan(vec.length); 122 123 vec[1 .. $ - 1].should == [1, 2, 3, 4, 5]; 124 } 125 126 @("assign") 127 @system unittest { 128 import std.range: iota; 129 auto vec = vector(10, 11, 12); 130 vec = 5.iota; 131 vec.range.should == [0, 1, 2, 3, 4]; 132 } 133 134 @("construct from range") 135 @safe unittest { 136 import std.range: iota; 137 vector(5.iota).range.should == [0, 1, 2, 3, 4]; 138 } 139 140 141 @("popBack") 142 @safe unittest { 143 auto vec = vector(0, 1, 2); 144 vec.popBack; 145 vec.range.should == [0, 1]; 146 } 147 148 @("popFront") 149 @safe unittest { 150 auto vec = vector(0, 1, 2, 3, 4); 151 vec.popFront; 152 vec.range.should == [1, 2, 3, 4]; 153 vec.empty.shouldBeFalse; 154 155 foreach(i; 0 .. vec.length) vec.popFront; 156 vec.empty.shouldBeTrue; 157 } 158 159 160 @("opSliceAssign") 161 @safe unittest { 162 auto vec = vector("foo", "bar", "quux", "toto"); 163 164 vec[] = "haha"; 165 vec.range.should == ["haha", "haha", "haha", "haha"]; 166 167 vec[1..3] = "oops"; 168 vec.range.should == ["haha", "oops", "oops", "haha"]; 169 } 170 171 @("opSliceOpAssign") 172 @safe unittest { 173 auto vec = vector("foo", "bar", "quux", "toto"); 174 vec[] ~= "oops"; 175 vec.range.should == ["foooops", "baroops", "quuxoops", "totooops"]; 176 } 177 178 @("opSliceOpAssign range") 179 @safe unittest { 180 auto vec = vector("foo", "bar", "quux", "toto"); 181 vec[1..3] ~= "oops"; 182 vec.range.should == ["foo", "baroops", "quuxoops", "toto"]; 183 } 184 185 @("clear") 186 @safe unittest { 187 auto vec = vector(0, 1, 2, 3); 188 vec.clear; 189 int[] empty; 190 vec.range.should ==(empty); 191 } 192 193 194 @("Mallocator elements") 195 @safe @nogc unittest { 196 import std.algorithm: equal; 197 auto vec = vector!Mallocator(0, 1, 2, 3); 198 int[4] exp = [0, 1, 2, 3]; 199 assert(equal(vec.range, exp[])); 200 } 201 202 @("Mallocator range") 203 @safe @nogc unittest { 204 import std.algorithm: equal; 205 import std.range: iota; 206 auto vec = vector!Mallocator(iota(5)); 207 int[5] exp = [0, 1, 2, 3, 4]; 208 assert(equal(vec.range, exp[])); 209 } 210 211 212 @("theAllocator null") 213 @safe unittest { 214 Vector!int vec; 215 } 216 217 218 @("Mallocator null") 219 @safe @nogc unittest { 220 Vector!(int, Mallocator) vec; 221 } 222 223 224 @("escape.range") 225 @safe @nogc unittest { 226 227 alias Ints = typeof(Vector!(int, Mallocator).init.range()); 228 229 Ints ints1; 230 scope vec = vector!Mallocator(0, 1, 2, 3); 231 Ints ints2; 232 233 static assert(!__traits(compiles, ints1 = vec.range)); 234 ints2 = vec.range; // should compile 235 } 236 237 238 @("escape.element") 239 @safe unittest { 240 241 int i = 1; 242 int j = 2; 243 244 int* oops; 245 scope vec = vector(&i, &j); 246 int* ok; 247 248 static assert(!__traits(compiles, oops = vec[0])); 249 ok = vec[0]; 250 } 251 252 253 @("TestAllocator elements capacity") 254 @system unittest { 255 static TestAllocator allocator; 256 257 auto vec = vector(&allocator, 0, 1, 2); 258 vec.range.should == [0, 1, 2]; 259 260 vec ~= 3; 261 vec ~= 4; 262 vec ~= 5; 263 vec ~= 6; 264 vec ~= 7; 265 vec ~= 8; 266 267 vec.range.should == [0, 1, 2, 3, 4, 5, 6, 7, 8]; 268 allocator.numAllocations.shouldBeSmallerThan(4); 269 } 270 271 @("TestAllocator reserve") 272 @system unittest { 273 static TestAllocator allocator; 274 275 auto vec = vector!(TestAllocator*, int)(&allocator); 276 277 vec.reserve(5); 278 () @trusted { vec.empty.should == true; }(); 279 280 vec ~= 0; 281 vec ~= 1; 282 vec ~= 2; 283 vec ~= 3; 284 vec ~= 4; 285 286 vec.range.should == [0, 1, 2, 3, 4]; 287 allocator.numAllocations.should == 1; 288 289 vec ~= 5; 290 vec.range.should == [0, 1, 2, 3, 4, 5]; 291 allocator.numAllocations.should == 2; 292 } 293 294 @("TestAllocator shrink no length") 295 @system unittest { 296 static TestAllocator allocator; 297 298 auto vec = vector!(TestAllocator*, int)(&allocator); 299 vec.reserve(10); 300 301 vec ~= 0; 302 vec ~= 1; 303 vec ~= 2; 304 vec ~= 3; 305 306 vec.length.should == 4; 307 vec.capacity.should == 10; 308 309 vec.shrink; 310 vec.length.should == 4; 311 vec.capacity.should == 4; 312 } 313 314 @("TestAllocator shrink negative number") 315 @system unittest { 316 static TestAllocator allocator; 317 318 auto vec = vector(&allocator, 0); 319 vec ~= 1; 320 vec ~= 2; 321 vec ~= 3; 322 vec.capacity.shouldBeGreaterThan(vec.length); 323 const oldCapacity = vec.capacity; 324 325 vec.shrink(-1).shouldBeFalse; 326 vec.capacity.should == oldCapacity; 327 } 328 329 @("TestAllocator shrink larger than capacity") 330 @system unittest { 331 static TestAllocator allocator; 332 333 auto vec = vector(&allocator, 0); 334 vec ~= 1; 335 vec ~= 2; 336 vec ~= 3; 337 vec.capacity.shouldBeGreaterThan(vec.length); 338 const oldCapacity = vec.capacity; 339 340 vec.shrink(oldCapacity * 2).shouldBeFalse; 341 vec.capacity.should == oldCapacity; 342 } 343 344 345 @("TestAllocator shrink with length") 346 @system unittest { 347 static TestAllocator allocator; 348 349 auto vec = vector(&allocator, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); 350 vec.capacity.should == 10; 351 352 vec.shrink(5); 353 vec.range.should == [0, 1, 2, 3, 4]; 354 vec.capacity.should == 5; 355 356 vec ~= 5; 357 vec.range.should == [0, 1, 2, 3, 4, 5]; 358 allocator.numAllocations.should == 3; 359 360 vec.reserve(10); 361 vec.length.should == 6; 362 vec.capacity.shouldBeGreaterThan(6); 363 } 364 365 @("TestAllocator copy") 366 @safe unittest { 367 static TestAllocator allocator; 368 369 auto vec1 = vector(&allocator, "foo", "bar", "baz"); 370 allocator.numAllocations.should == 1; 371 372 auto vec2 = vec1; 373 allocator.numAllocations.should == 2; 374 } 375 376 @("TestAllocator move") 377 @safe unittest { 378 static TestAllocator allocator; 379 380 auto vec = vector(&allocator, "foo", "bar", "baz"); 381 allocator.numAllocations.should == 1; 382 383 consumeVec(vec); 384 allocator.numAllocations.should == 1; 385 } 386 387 388 private void consumeVec(T)(auto ref T vec) { 389 390 } 391 392 393 @("set length") 394 @system unittest { 395 Vector!int vec; 396 vec.length = 3; 397 vec.range.should == [0, 0, 0]; 398 } 399 400 401 @("foreach") 402 @safe unittest { 403 foreach(e; vector(7, 7, 7).range) { 404 e.should == 7; 405 } 406 } 407 408 409 @("equal") 410 @safe unittest { 411 import std.range: iota; 412 import std.algorithm: equal; 413 414 auto v = vector(0, 1, 2, 3); 415 assert(equal(v.range, 4.iota)); 416 } 417 418 419 @("bool") 420 @safe unittest { 421 vector(0, 1, 2).shouldBeTrue; 422 Vector!int v; 423 if(v) { 424 assert(0); 425 } 426 } 427 428 @("char") 429 @system unittest { 430 { 431 auto vec = vector('f', 'o', 'o'); 432 vec.range.should ==("foo"); 433 vec ~= 'b'; 434 vec ~= ['a', 'r']; 435 vec.range.should ==("foobar"); 436 vec ~= "quux"; 437 vec.range.should ==("foobarquux"); 438 } 439 440 { 441 auto vec = vector("foo"); 442 vec.range.should ==("foo"); 443 vec.popBack; 444 vec.range.should ==("fo"); 445 } 446 447 { 448 auto vec = vector("foo"); 449 vec ~= "bar"; 450 vec.range.should ==("foobar"); 451 } 452 } 453 454 455 @("immutable.append") 456 @system unittest { 457 Vector!(immutable int) vec; 458 vec ~= 42; 459 vec.range.should == [42]; 460 } 461 462 463 @("String") 464 @safe unittest { 465 foreach(c; String("oooooo").range) 466 c.should == 'o'; 467 } 468 469 @("stringz") 470 @safe unittest { 471 import std..string: fromStringz; 472 auto str = vector("foobar"); 473 const strz = () @trusted { return str.stringz; }(); 474 const back = () @trusted { return fromStringz(strz); }(); 475 back.should == "foobar"; 476 str.range.should ==("foobar"); 477 } 478 479 480 @("ptr") 481 @safe unittest { 482 const vec = vector(0, 1, 2, 3); 483 takesScopePtr(vec.ptr); 484 () @trusted { vec.ptr[1].should == 1; }(); 485 } 486 487 private void takesScopePtr(T)(scope const(T)* ptr) { 488 489 } 490 491 492 @("StackFront") 493 @safe @nogc unittest { 494 import std.algorithm: equal; 495 import std.experimental.allocator.showcase: StackFront; 496 import std.experimental.allocator.mallocator: Mallocator; 497 498 alias Allocator = StackFront!(1024, Mallocator); 499 500 { 501 Vector!(int, Allocator) v; 502 () @trusted { v ~= 1; }(); 503 { 504 int[1] expected = [1]; 505 assert(equal(v.range, expected[])); 506 } 507 } 508 509 { 510 static void fun(Allocator)(ref Allocator allocator) { 511 Vector!(int, Allocator) v; 512 } 513 } 514 } 515 516 517 version(Windows) {} 518 else { 519 @("mmapRegionList") 520 @system unittest { 521 import std.experimental.allocator.showcase: mmapRegionList; 522 import std.experimental.allocator.mallocator: Mallocator; 523 import automem.vector: isAllocator; 524 525 auto v = vector(mmapRegionList(1024), 0, 1, 2); 526 v ~= 3; 527 } 528 } 529 530 531 532 @("2d") 533 @safe unittest { 534 auto v = vector(vector(0, 0, 0), vector(1, 1, 1, 1)); 535 v[0].range.should == [0, 0, 0]; 536 v[1].range.should == [1, 1, 1, 1]; 537 } 538 539 540 @("toString") 541 @safe unittest { 542 import std.conv: text; 543 auto v = vector(1, 2, 3); 544 v.range.text.should == `[1, 2, 3]`; 545 } 546 547 548 @("return") 549 @system unittest { 550 551 static auto fun() { 552 auto v = vector(1, 2, 3); 553 v ~= 4; 554 return v; 555 } 556 557 auto v = fun; 558 v ~= 5; 559 v.range.should == [1, 2, 3, 4, 5]; 560 } 561 562 563 @("noconsume.range") 564 @safe unittest { 565 import std.algorithm: equal; 566 567 scope v = vector(1, 2, 3); 568 569 static void fun(R)(R range) { 570 import std.array: array; 571 assert(equal(range, [1, 2, 3])); 572 } 573 574 fun(v.range); 575 assert(equal(v.range, [1, 2, 3])); 576 } 577 578 579 @("noconsume.foreach") 580 @safe unittest { 581 scope v = vector(1, 2, 3); 582 foreach(e; v.range) {} 583 v.range.should == [1, 2, 3]; 584 } 585 586 587 @("noconsume.map") 588 @safe unittest { 589 import std.algorithm: map; 590 591 scope v = vector(1, 2, 3); 592 v.range.map!(a => a * 2).should == [2, 4, 6]; 593 v.range.should == [1, 2, 3]; 594 } 595 596 597 @("reserve") 598 @safe unittest { 599 scope vec = vector(1, 2, 3); 600 vec.range.should == [1, 2, 3]; 601 () @trusted { vec.reserve(10); }(); 602 vec.range.should == [1, 2, 3]; 603 } 604 605 606 @("range.reserve") 607 @safe unittest { 608 scope vec = vector(1, 2, 3); 609 scope range = vec.range; 610 611 range.save.should == [1, 2, 3]; 612 () @trusted { vec.reserve(10); }(); 613 614 range.should == [1, 2, 3]; 615 } 616 617 618 @("range.const") 619 @safe unittest { 620 const vec = vector(1, 2, 3); 621 vec.range.should == [1, 2, 3]; 622 } 623 624 625 @("range.bounds") 626 @safe unittest { 627 const vec = vector(1, 2, 3, 4, 5); 628 vec.range(1, 4).should == [2, 3, 4]; 629 vec.range(2, vec.length).should == [3, 4, 5]; 630 vec.range(2, -1).should == [3, 4, 5]; 631 vec.range(2, -2).should == [3, 4]; 632 } 633 634 635 @("equals") 636 @safe unittest { 637 import std.range: iota, only; 638 639 const vec = vector(0, 1, 2); 640 641 (vec == 3.iota).should == true; 642 (vec == 2.iota).should == false; 643 (vec == 4.iota).should == false; 644 (vec == only(0)).should == false; 645 }