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 @system 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 @system 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 @system 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 // Taking address of `ref` return not allowed in older dmd versions 249 static if (__VERSION__ >= 2101) 250 { 251 static assert(!__traits(compiles, oops = &vec[0])); 252 ok = &vec[0]; 253 } 254 } 255 256 257 @("TestAllocator elements capacity") 258 @system unittest { 259 static TestAllocator allocator; 260 261 auto vec = vector(&allocator, 0, 1, 2); 262 vec.range.should == [0, 1, 2]; 263 264 vec ~= 3; 265 vec ~= 4; 266 vec ~= 5; 267 vec ~= 6; 268 vec ~= 7; 269 vec ~= 8; 270 271 vec.range.should == [0, 1, 2, 3, 4, 5, 6, 7, 8]; 272 allocator.numAllocations.shouldBeSmallerThan(4); 273 } 274 275 @("TestAllocator reserve") 276 @system unittest { 277 static TestAllocator allocator; 278 279 auto vec = vector!(TestAllocator*, int)(&allocator); 280 281 vec.reserve(5); 282 () @trusted { vec.empty.should == true; }(); 283 284 vec ~= 0; 285 vec ~= 1; 286 vec ~= 2; 287 vec ~= 3; 288 vec ~= 4; 289 290 vec.range.should == [0, 1, 2, 3, 4]; 291 allocator.numAllocations.should == 1; 292 293 vec ~= 5; 294 vec.range.should == [0, 1, 2, 3, 4, 5]; 295 allocator.numAllocations.should == 2; 296 } 297 298 @("TestAllocator shrink no length") 299 @system unittest { 300 static TestAllocator allocator; 301 302 auto vec = vector!(TestAllocator*, int)(&allocator); 303 vec.reserve(10); 304 305 vec ~= 0; 306 vec ~= 1; 307 vec ~= 2; 308 vec ~= 3; 309 310 vec.length.should == 4; 311 vec.capacity.should == 10; 312 313 vec.shrink; 314 vec.length.should == 4; 315 vec.capacity.should == 4; 316 } 317 318 @("TestAllocator shrink negative number") 319 @system unittest { 320 static TestAllocator allocator; 321 322 auto vec = vector(&allocator, 0); 323 vec ~= 1; 324 vec ~= 2; 325 vec ~= 3; 326 vec.capacity.shouldBeGreaterThan(vec.length); 327 const oldCapacity = vec.capacity; 328 329 vec.shrink(-1).shouldBeFalse; 330 vec.capacity.should == oldCapacity; 331 } 332 333 @("TestAllocator shrink larger than capacity") 334 @system unittest { 335 static TestAllocator allocator; 336 337 auto vec = vector(&allocator, 0); 338 vec ~= 1; 339 vec ~= 2; 340 vec ~= 3; 341 vec.capacity.shouldBeGreaterThan(vec.length); 342 const oldCapacity = vec.capacity; 343 344 vec.shrink(oldCapacity * 2).shouldBeFalse; 345 vec.capacity.should == oldCapacity; 346 } 347 348 349 @("TestAllocator shrink with length") 350 @system unittest { 351 static TestAllocator allocator; 352 353 auto vec = vector(&allocator, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); 354 vec.capacity.should == 10; 355 356 vec.shrink(5); 357 vec.range.should == [0, 1, 2, 3, 4]; 358 vec.capacity.should == 5; 359 360 vec ~= 5; 361 vec.range.should == [0, 1, 2, 3, 4, 5]; 362 allocator.numAllocations.should == 3; 363 364 vec.reserve(10); 365 vec.length.should == 6; 366 vec.capacity.shouldBeGreaterThan(6); 367 } 368 369 @("TestAllocator copy") 370 @safe unittest { 371 static TestAllocator allocator; 372 373 auto vec1 = vector(&allocator, "foo", "bar", "baz"); 374 allocator.numAllocations.should == 1; 375 376 auto vec2 = vec1; 377 allocator.numAllocations.should == 2; 378 } 379 380 @("TestAllocator move") 381 @safe unittest { 382 static TestAllocator allocator; 383 384 auto vec = vector(&allocator, "foo", "bar", "baz"); 385 allocator.numAllocations.should == 1; 386 387 consumeVec(vec); 388 allocator.numAllocations.should == 1; 389 } 390 391 392 private void consumeVec(T)(auto ref T vec) { 393 394 } 395 396 397 @("set length") 398 @system unittest { 399 Vector!int vec; 400 vec.length = 3; 401 vec.range.should == [0, 0, 0]; 402 } 403 404 405 @("foreach") 406 @safe unittest { 407 foreach(e; vector(7, 7, 7).range) { 408 e.should == 7; 409 } 410 } 411 412 413 @("equal") 414 @safe unittest { 415 import std.range: iota; 416 import std.algorithm: equal; 417 418 auto v = vector(0, 1, 2, 3); 419 assert(equal(v.range, 4.iota)); 420 } 421 422 423 @("bool") 424 @safe unittest { 425 vector(0, 1, 2).shouldBeTrue; 426 Vector!int v; 427 if(v) { 428 assert(0); 429 } 430 } 431 432 @("char") 433 @system unittest { 434 { 435 auto vec = vector('f', 'o', 'o'); 436 vec.range.should ==("foo"); 437 vec ~= 'b'; 438 vec ~= ['a', 'r']; 439 vec.range.should ==("foobar"); 440 vec ~= "quux"; 441 vec.range.should ==("foobarquux"); 442 } 443 444 { 445 auto vec = vector("foo"); 446 vec.range.should ==("foo"); 447 vec.popBack; 448 vec.range.should ==("fo"); 449 } 450 451 { 452 auto vec = vector("foo"); 453 vec ~= "bar"; 454 vec.range.should ==("foobar"); 455 } 456 } 457 458 459 @("immutable.append") 460 @system unittest { 461 Vector!(immutable int) vec; 462 vec ~= 42; 463 vec.range.should == [42]; 464 } 465 466 467 @("String") 468 @safe unittest { 469 foreach(c; String("oooooo").range) 470 c.should == 'o'; 471 } 472 473 @("stringz") 474 @safe unittest { 475 import std.string: fromStringz; 476 auto str = vector("foobar"); 477 const strz = () @trusted { return str.stringz; }(); 478 const back = () @trusted { return fromStringz(strz); }(); 479 back.should == "foobar"; 480 str.range.should ==("foobar"); 481 } 482 483 484 @("ptr") 485 @safe unittest { 486 const vec = vector(0, 1, 2, 3); 487 takesScopePtr(vec.ptr); 488 () @trusted { vec.ptr[1].should == 1; }(); 489 } 490 491 private void takesScopePtr(T)(scope const(T)* ptr) { 492 493 } 494 495 496 @("StackFront") 497 @safe @nogc unittest { 498 import std.algorithm: equal; 499 import std.experimental.allocator.showcase: StackFront; 500 import std.experimental.allocator.mallocator: Mallocator; 501 502 alias Allocator = StackFront!(1024, Mallocator); 503 504 { 505 Vector!(int, Allocator) v; 506 () @trusted { v ~= 1; }(); 507 { 508 int[1] expected = [1]; 509 assert(equal(v.range, expected[])); 510 } 511 } 512 513 { 514 static void fun(Allocator)(ref Allocator allocator) { 515 Vector!(int, Allocator) v; 516 } 517 } 518 } 519 520 521 version(Windows) {} 522 else { 523 @("mmapRegionList") 524 @system unittest { 525 import std.experimental.allocator.showcase: mmapRegionList; 526 import std.experimental.allocator.mallocator: Mallocator; 527 import automem.vector: isAllocator; 528 529 auto v = vector(mmapRegionList(1024), 0, 1, 2); 530 v ~= 3; 531 } 532 } 533 534 535 536 @("2d") 537 @safe unittest { 538 auto v = vector(vector(0, 0, 0), vector(1, 1, 1, 1)); 539 v[0].range.should == [0, 0, 0]; 540 v[1].range.should == [1, 1, 1, 1]; 541 } 542 543 544 @("toString") 545 @safe unittest { 546 import std.conv: text; 547 auto v = vector(1, 2, 3); 548 v.range.text.should == `[1, 2, 3]`; 549 } 550 551 552 @("return") 553 @system unittest { 554 555 static auto fun() { 556 auto v = vector(1, 2, 3); 557 v ~= 4; 558 return v; 559 } 560 561 auto v = fun; 562 v ~= 5; 563 v.range.should == [1, 2, 3, 4, 5]; 564 } 565 566 567 @("noconsume.range") 568 @safe unittest { 569 import std.algorithm: equal; 570 571 scope v = vector(1, 2, 3); 572 573 static void fun(R)(R range) { 574 import std.array: array; 575 assert(equal(range, [1, 2, 3])); 576 } 577 578 fun(v.range); 579 assert(equal(v.range, [1, 2, 3])); 580 } 581 582 583 @("noconsume.foreach") 584 @safe unittest { 585 scope v = vector(1, 2, 3); 586 foreach(e; v.range) {} 587 v.range.should == [1, 2, 3]; 588 } 589 590 591 @("noconsume.map") 592 @safe unittest { 593 import std.algorithm: map; 594 595 scope v = vector(1, 2, 3); 596 v.range.map!(a => a * 2).should == [2, 4, 6]; 597 v.range.should == [1, 2, 3]; 598 } 599 600 601 @("reserve") 602 @safe unittest { 603 scope vec = vector(1, 2, 3); 604 vec.range.should == [1, 2, 3]; 605 () @trusted { vec.reserve(10); }(); 606 vec.range.should == [1, 2, 3]; 607 } 608 609 610 @("range.reserve") 611 @safe unittest { 612 scope vec = vector(1, 2, 3); 613 scope range = vec.range; 614 615 range.save.should == [1, 2, 3]; 616 () @trusted { vec.reserve(10); }(); 617 618 range.should == [1, 2, 3]; 619 } 620 621 622 @("range.const") 623 @safe unittest { 624 const vec = vector(1, 2, 3); 625 vec.range.should == [1, 2, 3]; 626 } 627 628 629 @("range.bounds") 630 @safe unittest { 631 const vec = vector(1, 2, 3, 4, 5); 632 vec.range(1, 4).should == [2, 3, 4]; 633 vec.range(2, vec.length).should == [3, 4, 5]; 634 vec.range(2, -1).should == [3, 4, 5]; 635 vec.range(2, -2).should == [3, 4]; 636 } 637 638 639 @("equals") 640 @safe unittest { 641 import std.range: iota, only; 642 643 const vec = vector(0, 1, 2); 644 645 (vec == 3.iota).should == true; 646 (vec == 2.iota).should == false; 647 (vec == 4.iota).should == false; 648 (vec == only(0)).should == false; 649 }