1 module ikod.containers.unrolledlist; 2 3 private import core.memory; 4 private import core.bitop; 5 private import core.exception; 6 7 private import std.experimental.allocator; 8 private import std.experimental.allocator.mallocator : Mallocator; 9 private import std.experimental.allocator.gc_allocator; 10 private import std.experimental.logger; 11 private import std.format; 12 private import std.algorithm; 13 private import std.typecons; 14 private import std.compiler; 15 16 private import automem.unique; 17 18 private import ikod.containers.internal; 19 20 /// 21 struct UnrolledList(T, Allocator = Mallocator, bool GCRangesAllowed = true) 22 { 23 invariant(_nodes_counter>=0 && _count>=0); 24 private: 25 alias allocator = Allocator.instance; 26 alias StoredT = StoredType!T; 27 enum ItemsPerNode = 32; // can be variable maybe 28 enum MaxRanges = 16; 29 enum NewItemPosition = ItemsPerNode/2; 30 // 31 int _count; 32 int _nodes_counter; 33 Node* _first_node, _last_node; 34 short _constRanges_counter; 35 short _mutRanges_counter; 36 Impl!"mut"*[MaxRanges] _mutRanges; 37 Impl!"const"*[MaxRanges] _constRanges; 38 39 struct Node 40 { 41 42 static assert(ItemsPerNode <= 32); 43 44 uint _count; 45 uint _bitmap; 46 Node* _next_node; 47 48 StoredT[ItemsPerNode] _items; 49 Node* _prev_node; 50 51 bool empty() @safe @nogc nothrow 52 { 53 return _bitmap == 0; 54 } 55 bool full() pure @safe @nogc nothrow 56 { 57 return _count == ItemsPerNode; 58 } 59 int count_free_high_bits() 60 in(_count>=0 && _count <= ItemsPerNode) 61 { 62 if ( _count == ItemsPerNode || test_bit(ItemsPerNode-1) ) 63 { 64 return 0; 65 } 66 if ( _count == 0 ) 67 { 68 return ItemsPerNode; 69 } 70 return(bsf(bitswap(_bitmap))); 71 } 72 int count_free_low_bits() 73 in(_count>=0 && _count <= ItemsPerNode) 74 { 75 if ( _count == ItemsPerNode || test_bit(0) ) 76 { 77 return 0; 78 } 79 if ( _count == 0 ) 80 { 81 return ItemsPerNode; 82 } 83 return(bsf(_bitmap)); 84 } 85 86 pragma(inline, true): 87 void mark_bit(size_t n) pure @safe @nogc 88 { 89 debug assert(n < ItemsPerNode, format("%s must be less than %d", n, ItemsPerNode)); 90 _bitmap |= 1 << n; 91 } 92 93 pragma(inline, true): 94 void clear_bit(size_t n) pure @safe @nogc nothrow 95 { 96 if ( n >= ItemsPerNode ) 97 { 98 debug throw new Exception("X"); 99 } 100 assert(n < ItemsPerNode); 101 _bitmap &= uint.max ^ (1 << n); 102 } 103 pragma(inline, true): 104 int _hi_mask(int pos) 105 { 106 return _bitmap >> pos; 107 } 108 pragma(inline, true): 109 int _lo_mask(int pos) 110 { 111 return bitswap((((1<<pos) - 1) & _bitmap) << (int.sizeof*8-pos)); 112 } 113 pragma(inline, true): 114 bool test_bit(size_t n) pure @safe @nogc nothrow 115 in(n<ItemsPerNode) 116 { 117 return cast(bool)(_bitmap & (1 << n)); 118 } 119 120 int translate_pos(int n) pure @safe @nogc nothrow 121 in( n < ItemsPerNode ) 122 out(result; result == -1 || result < ItemsPerNode) 123 { 124 if (_count == ItemsPerNode ) 125 { 126 return cast(int)n; 127 } 128 if ( _count <= n ) 129 { 130 return -1; 131 } 132 int p = 0; 133 foreach(i; bsf(_bitmap)..ItemsPerNode) 134 { 135 if ( !test_bit(i)) continue; 136 if (p == n) 137 { 138 return i; 139 } 140 p++; 141 } 142 assert(0); 143 } 144 } 145 146 Node* _free_list; 147 int _free_list_count; 148 149 Node* makeNode() 150 { 151 if ( _free_list_count > 0 ) 152 { 153 Node* n = _free_list; 154 _free_list_count--; 155 _free_list = n._next_node; 156 n._prev_node = n._next_node = null; 157 n._count = n._bitmap = 0; 158 return n; 159 } 160 Node* node = make!Node(allocator); 161 static if ( UseGCRanges!(Allocator, T, GCRangesAllowed) ) { 162 () @trusted { 163 GC.addRange(&node._items[0], T.sizeof * ItemsPerNode); 164 }(); 165 } 166 return node; 167 } 168 void deallocNode(Node *p) 169 { 170 if (_free_list_count < 100) 171 { 172 _free_list_count++; 173 p._next_node = _free_list; 174 _free_list = p; 175 return; 176 } 177 () @trusted { 178 static if ( UseGCRanges!(Allocator,T, GCRangesAllowed) ) { 179 GC.removeRange(&p._items[0]); 180 } 181 dispose(allocator, p); 182 }(); 183 } 184 enum Sig 185 { 186 CLEAR = 0, 187 REMOVE, 188 INSERT 189 } 190 /++ 191 +/ 192 public struct Iterator(I) 193 { 194 private I* _impl; 195 package this(Args...)(auto ref Args args, string file = __FILE__, int line = __LINE__) @trusted 196 { 197 import std.functional: forward; 198 import std.conv: emplace; 199 _impl = cast(typeof(_impl)) allocator.allocate((*_impl).sizeof); 200 emplace(_impl, forward!args); 201 } 202 this(this) @safe 203 { 204 if (!_impl) 205 { 206 return; 207 } 208 auto _new_impl = () @trusted {return cast(typeof(_impl)) allocator.allocate((*_impl).sizeof);}(); 209 _new_impl._list = null; 210 _new_impl._ptr = null; 211 *_new_impl = *_impl; 212 _impl = _new_impl; 213 } 214 ~this() 215 { 216 _impl.reset(); 217 () @trusted {allocator.dispose(_impl);}(); 218 } 219 /// test on emptiness 220 bool empty() 221 { 222 return _impl.empty(); 223 } 224 /// return front element of iterator 225 auto front() 226 { 227 return _impl.front(); 228 } 229 /// pop front element 230 void popFront() 231 { 232 _impl.popFront(); 233 } 234 // save 235 auto save() 236 { 237 return this; 238 } 239 /// reset iterator 240 void reset() 241 { 242 _impl.reset(); 243 } 244 int opApply(scope int delegate(T) dg) 245 { 246 int result = 0; 247 while(!empty) 248 { 249 result = dg(front); 250 popFront; 251 if (result) 252 break; 253 } 254 return result; 255 } 256 static if (is(I == Impl!"mut")) 257 { 258 void set(T v) 259 { 260 auto list = _impl._list; 261 assert(list._constRanges_counter == 0); 262 auto node = _impl._currentNode; 263 auto pos = _impl._currentNodeItemPosition; 264 assert(node.test_bit(pos)); 265 node._items[pos] = v; 266 } 267 /// 268 /// remove current front Item from list 269 /// +--------------+-----------------------+-----------------+ 270 /// | this | other | list | 271 /// | Iter | Iter | | 272 /// +--------------+-----------------------+-----------------+ 273 /// | remove list | if points to removed: | free item; | 274 /// | item; | mark invalid | adjust counters | 275 /// | do popFront; | else: | | 276 /// | | adjust everything | | 277 /// +--------------+-----------------------+-----------------+ 278 /// 279 void remove() 280 { 281 auto list = _impl._list; 282 assert(list._constRanges_counter == 0); 283 auto node = _impl._currentNode; 284 auto pos = _impl._currentNodeItemPosition; 285 //debug infof("before remove item: %d, node= %s, pos=%s", _impl._item, _impl._currentNode, _impl._currentNodeItemPosition); 286 assert(node.test_bit(pos)); 287 if ( list._mutRanges_counter > 0) foreach(mr; list._mutRanges) 288 { 289 if (mr !is null && mr != this._impl) 290 { 291 // debug infof("callback %x", mr); 292 mr.signal(Sig.REMOVE, _impl._item, node, _impl._currentNodeItem); 293 } 294 } 295 list._count--; 296 node._count--; 297 //_impl._item--; 298 _impl._end--; 299 _impl._currentNodeItemsTotal--; 300 node.clear_bit(pos); 301 node._items[pos] = T.init; 302 // debug infof("after remove item: %d", _impl._item); 303 if ( _impl._item == _impl._end) 304 { 305 // debug info("become empty"); 306 _impl._empty = true; 307 return; 308 } 309 if ( _impl._currentNodeItem == node._count ) 310 { 311 // debug info("jump next node"); 312 node = node._next_node; 313 while (node && node._count == 0 ) 314 { 315 // debug info("jump next node"); 316 auto next_node = node._next_node; 317 if ( list._constRanges_counter == 0 && list._mutRanges_counter == 1) 318 { 319 // safe to remove empty node 320 if ( _impl._currentNode ) 321 { 322 _impl._currentNodeItemsTotal = _impl._currentNode._count; 323 } 324 if ( node == list._first_node ) 325 { 326 list._first_node = node._next_node; 327 } 328 if ( node == list._last_node ) 329 { 330 list._last_node = node._prev_node; 331 } 332 if ( node._prev_node ) 333 { 334 node._prev_node._next_node = node._next_node; 335 } 336 if ( node._next_node ) 337 { 338 node._next_node._prev_node = node._prev_node; 339 } 340 list._nodes_counter--; 341 list.deallocNode(node); 342 } 343 node = next_node; 344 } 345 _impl._currentNodeItem = 0; 346 _impl._currentNode = node; 347 _impl._currentNodeItemsTotal = node._count; 348 } 349 _impl._currentNodeItemPosition = node.translate_pos(_impl._currentNodeItem); 350 // debug infof("after remove item: %d, node= %s, pos=%s", _impl._item, _impl._currentNode, _impl._currentNodeItemPosition); 351 } 352 void insert(T v) 353 { 354 auto list = _impl._list; 355 Node* node = _impl._currentNode; 356 int pos = _impl._currentNodeItemPosition; 357 if ( list._mutRanges_counter > 0) foreach(mr; list._mutRanges) 358 { 359 if (mr !is null && mr != this._impl) 360 { 361 // debug infof("callback %x", mr); 362 mr.signal(Sig.INSERT, _impl._item, node, _impl._currentNodeItem); 363 } 364 } 365 if ( _impl._empty ) 366 { 367 // debug info("insert to empty range"); 368 // debug infof("it_item: %s, it_end: %s, it_nodeItem: %s", _impl._item, _impl._end, _impl._currentNodeItem); 369 // debug infof("list_end: %s", _impl._list._count); 370 list._doRealPushBack(v); 371 _impl._end++; 372 _impl._item++; 373 return; 374 } 375 _impl._end++; 376 _impl._item++; 377 assert(_impl._currentNodeItemPosition>=0); 378 int lo_mask = node._lo_mask(pos); 379 int hi_mask = node._hi_mask(pos); 380 int lo_shift = lo_mask != 0 ? bsf(lo_mask ^ uint.max) : 381 pos == 0 ? uint.max : 0; 382 int hi_shift = hi_mask == 0 ? uint.max : bsf(hi_mask ^ uint.max); 383 auto lo_overflow = lo_shift < hi_shift && lo_shift >= pos; 384 auto hi_overflow = hi_shift <= lo_shift && pos + hi_shift >= ItemsPerNode; 385 auto nodeItem = _impl._currentNodeItem; 386 // debug infof("nodeItemPos: %s", pos); 387 // debug infof("nodeItem: %s", nodeItem); 388 // debug infof("bitmap %32.32b", node._bitmap); 389 // debug infof("lomask %32.32b", lo_mask); 390 // debug infof("himask %32.32b", hi_mask); 391 // debug infof("lo_shift: %d, hi shift: %d", lo_shift, hi_shift); 392 // debug infof("lo_over: %s, hi overfl: %s", lo_overflow, hi_overflow); 393 394 _impl._list._doRealInsert(node, nodeItem, v); 395 396 if (!lo_overflow && !hi_overflow && lo_shift != -1) 397 { 398 _impl._currentNodeItem++; 399 _impl._currentNodeItemsTotal++; 400 if ( lo_shift >= hi_shift) 401 { 402 _impl._currentNodeItemPosition++; 403 } 404 } 405 if ( hi_overflow ) 406 { 407 _impl._currentNodeItem++; 408 _impl._currentNodeItemPosition++; 409 } 410 if (_impl._currentNodeItem >= _impl._currentNodeItemsTotal) 411 { 412 _impl._currentNodeItem = 0; 413 _impl._currentNode = _impl._currentNode._next_node; 414 if ( _impl._currentNode ) 415 { 416 _impl._currentNodeItemPosition = _impl._currentNode.translate_pos(0); 417 _impl._currentNodeItemsTotal = _impl._currentNode._count; 418 } 419 } 420 // debug infof("nodeItem: %s", _impl._currentNodeItem); 421 } 422 } 423 } 424 425 template Impl(string kind) if (kind == "mut" || kind == "const") 426 { 427 alias ListType = typeof(this); 428 alias NodeType = ListType.Node; 429 struct Impl 430 { 431 alias T = typeof(this); 432 T** _ptr; 433 ListType* _list; 434 bool _empty; 435 NodeType* _currentNode; 436 int _currentNodeItem; 437 int _currentNodeItemPosition; // in bitmap 438 int _currentNodeItemsTotal; 439 int _item; 440 size_t _end; 441 442 static if (kind == "mut") 443 { 444 private auto refc() 445 { 446 return &_list._mutRanges_counter; 447 } 448 private auto refptr(int i) 449 { 450 return &_list._mutRanges[i]; 451 } 452 // Params: sig - signal type 453 // i - index of the item inside node 454 // n - node 455 void signal(Sig sig, int item, Node* n, int nodeItem) nothrow 456 { 457 final switch(sig) 458 { 459 case Sig.CLEAR: 460 _item = 0; 461 _end = 0; 462 _empty = true; 463 _currentNode = null; 464 _currentNodeItem = 0; 465 return; 466 case Sig.REMOVE: 467 if ( _empty ) 468 { 469 // nothing to do 470 return; 471 } 472 // debug infof("signal remove: old item# %s, i'm at %s, end: %s", item, _item, _end); 473 if ( item <= _item ) 474 { 475 // ,-remove 476 // ___X___b....e___ 477 _item--; 478 _end--; 479 if ( n != _currentNode ) 480 { 481 return; 482 } 483 _currentNodeItem--; 484 _currentNodeItemsTotal--; 485 if (_currentNodeItemsTotal == 0) 486 { 487 // goto next node 488 while(n && n._next_node && n._next_node._count == 0) 489 { 490 n = n._next_node; 491 } 492 n = n._next_node; 493 _currentNode = n; 494 _currentNodeItem = -1; 495 //_currentNodeItemPosition = cast(ubyte)bsf(n._bitmap); 496 if ( n ) _currentNodeItemsTotal = cast(short)n._count; 497 } 498 return; 499 } 500 if ( _item <= item && item < _end ) 501 { 502 // ,-remove 503 // _b.X....e___ 504 _end--; 505 if ( n != _currentNode ) 506 { 507 return; 508 } 509 _currentNodeItemsTotal--; 510 return; 511 } 512 // ,-remove 513 // _b.....e__X__ 514 // nothing to do 515 break; 516 case Sig.INSERT: 517 // debug infof("signal insert: old item# %s, i'm at %s, end: %s", item, _item, _end); 518 if ( item >= _end) 519 { 520 // debug info("insert after end"); 521 return; 522 } 523 if ( item <= _item ) 524 { 525 _item++; 526 if (n == _currentNode) 527 { 528 _currentNodeItem++; 529 } 530 } 531 if (n !is null && n == _currentNode) 532 { 533 auto pos = n.translate_pos(nodeItem); 534 535 int lo_mask = n._lo_mask(pos); 536 int hi_mask = n._hi_mask(pos); 537 538 int lo_shift = lo_mask != 0 ? bsf(lo_mask ^ uint.max) : 539 pos == 0 ? uint.max : 0; 540 int hi_shift = hi_mask == 0 ? uint.max : bsf(hi_mask ^ uint.max); 541 auto lo_overflow = lo_shift < hi_shift && lo_shift >= pos; 542 auto hi_overflow = hi_shift <= lo_shift && pos + hi_shift >= ItemsPerNode; 543 // debug infof("lomask %32.32b", lo_mask); 544 // debug infof("himask %32.32b", hi_mask); 545 // debug infof("lo_shift: %d, hi shift: %d", lo_shift, hi_shift); 546 // debug infof("lo_over: %s, hi overfl: %s", lo_overflow, hi_overflow); 547 548 549 if ( lo_overflow && _currentNodeItemPosition == 0) 550 { 551 // debug info("going to move left"); 552 // this item becomes highest item in the prev node 553 Node* prev_node = n._prev_node; 554 int prev_pos = prev_node.translate_pos(prev_node._count-1)+1; 555 // debug infof("my new position: %d", prev_pos); 556 _currentNode = prev_node; 557 _currentNodeItem = _currentNode._count; 558 _currentNodeItemsTotal = _currentNode._count+1; 559 _currentNodeItemPosition = prev_pos; 560 } 561 else 562 { 563 int p = n.translate_pos(nodeItem); 564 if ( (_currentNodeItemPosition < p) && (lo_shift < hi_shift)) 565 { 566 // we might be affectd by the left shift 567 // debug infof("my pos = %s, his pos = %s", _currentNodeItemPosition, p); 568 if ( p - _currentNodeItemPosition < lo_shift ) 569 { 570 // we shifted left 571 _currentNodeItemPosition--; 572 assert(_currentNodeItemPosition>=0); 573 } 574 } 575 if (!hi_overflow) 576 { 577 _currentNodeItemsTotal = _currentNode._count+1; 578 } 579 } 580 _end++; 581 // debug infof("_item: %d, _nodeItem: %d, _currentNodeItemsTotal: %s", _item, _currentNodeItem, _currentNodeItemsTotal); 582 return; 583 } 584 if ( n !is null && n == _currentNode._next_node ) 585 { 586 n = _currentNode._next_node; 587 auto pos = n.translate_pos(nodeItem); 588 589 int lo_mask = n._lo_mask(pos); 590 int hi_mask = n._hi_mask(pos); 591 592 int lo_shift = lo_mask != 0 ? bsf(lo_mask ^ uint.max) : 593 pos == 0 ? uint.max : 0; 594 int hi_shift = hi_mask == 0 ? -1 : bsf(hi_mask ^ uint.max); 595 auto lo_overflow = lo_shift < hi_shift && lo_shift >= pos; 596 auto hi_overflow = hi_shift <= lo_shift && pos + hi_shift >= ItemsPerNode; 597 598 // debug infof("lomask2 %32.32b", lo_mask); 599 // debug infof("himask2 %32.32b", hi_mask); 600 // debug infof("lo_shift2: %d, hi shift2: %d", lo_shift, hi_shift); 601 // debug infof("lo_over2: %s, hi overfl2: %s", lo_overflow, hi_overflow); 602 603 if ( (lo_overflow || lo_shift==-1) && _currentNode.count_free_high_bits()>0) 604 { 605 // debug infof("will overflow to me, new _currentNodeItemsTotal: %s", _currentNodeItemsTotal+1); 606 // overflow to my node from 607 _currentNodeItemsTotal++; 608 } 609 _end++; 610 return; 611 } 612 _end++; 613 // debug infof("signal insert: new item# %d, new end: %d", item, _end); 614 break; 615 } 616 } 617 } 618 else 619 { 620 private auto refc() 621 { 622 return &_list._constRanges_counter; 623 } 624 private auto refptr(int i) 625 { 626 return &_list._constRanges[i]; 627 } 628 } 629 public: 630 this(T** p, ListType* list = null, int item = 0, int end = 0, NodeType* node = null, int nodeItem = 0) @nogc 631 { 632 _ptr = p; 633 if (p) 634 { 635 *_ptr = &this; 636 } 637 _list = list; 638 _item = item; 639 _end = end; 640 _currentNode = node; 641 _currentNodeItem = nodeItem; 642 if (node) 643 { 644 _currentNodeItemsTotal = node._count; 645 _currentNodeItemPosition = node.translate_pos(nodeItem); 646 } 647 } 648 /// create and register another instance of stable range 649 this(this) 650 { 651 if ( !_list || !_ptr ) 652 { 653 return; 654 } 655 for(auto i=0; i<MaxRanges; i++) 656 { 657 if ( *refptr(i) is null ) 658 { 659 (*refc)++; 660 *refptr(i) = &this; 661 _ptr = refptr(i); 662 return; 663 } 664 } 665 assert(0, "Too much active stable ranges"); 666 } 667 ~this() @safe 668 { 669 if ( _list !is null ) 670 { 671 (*refc)--; 672 assert((*refc) >= 0); 673 } 674 if (_ptr !is null) 675 { 676 *_ptr = null; 677 } 678 } 679 auto opAssign(V)(auto ref V other) if (is(V==typeof(this))) 680 { 681 if ( other is this ) 682 { 683 return; 684 } 685 if ( _list && other._list != _list ) 686 { 687 reset(); 688 } 689 if ( _ptr is null && other._list !is null ) 690 { 691 // register 692 assert(_list is null); 693 _list = other._list; 694 for(auto i=0; i<MaxRanges; i++) 695 { 696 if ( *refptr(i) is null ) 697 { 698 (*refc)++; 699 assert(*refc < _list.MaxRanges); 700 *refptr(i) = &this; 701 _ptr = refptr(i); 702 break; 703 } 704 } 705 } 706 _item = other._item; 707 _end = other._end; 708 _currentNode = other._currentNode; 709 _currentNodeItem = other._currentNodeItem; 710 _currentNodeItemsTotal = other._currentNodeItemsTotal; 711 _currentNodeItemPosition = other._currentNodeItemPosition; 712 _empty = other._empty; 713 } 714 void reset() 715 { 716 if (_list is null || _ptr is null ) 717 { 718 assert(_list is null && _ptr is null); 719 return; 720 } 721 assert(_list !is null); 722 (*refc)--; 723 assert(*refc >= 0); 724 if ( _ptr !is null ) 725 { 726 assert(*_ptr == &this); 727 *_ptr = null; 728 _ptr = null; 729 } 730 _list = null; 731 } 732 auto front() 733 { 734 assert(_list && _currentNode); 735 auto n = _currentNode; 736 auto p = _currentNodeItemPosition; 737 assert(_item >= 0); 738 assert(n.test_bit(p), "You tried to access empty item."); 739 return n._items[p]; 740 } 741 void popFront() 742 { 743 // if ( !_list || !_ptr ) 744 // { 745 // return; 746 // } 747 // debug infof("popping from item %s, nodeItem: %s", _item, _currentNodeItem); 748 _item++; 749 if ( _item >= _end ) 750 { 751 _empty = true; 752 static if (kind == "const") 753 { 754 reset(); 755 } 756 return; 757 } 758 auto n = _currentNode; 759 if ( !n ) 760 { 761 debug throw new Exception("y"); 762 } 763 assert(n); 764 _currentNodeItem++; 765 // debug infof("_item=%s, _end=%s, _currentnodeItem now =%s, _currentNodeItems = %s", _item, _end, _currentNodeItem, _currentNodeItemsTotal); 766 if ( _currentNodeItem == _currentNodeItemsTotal ) 767 { 768 // debug infof("jump next node"); 769 // goto next node 770 while(n && n._next_node && n._next_node._count == 0) 771 { 772 //debug infof("skip empty node"); 773 n = n._next_node; 774 } 775 n = n._next_node; 776 _currentNode = n; 777 _currentNodeItem = 0; 778 _currentNodeItemPosition = cast(ubyte)bsf(n._bitmap); 779 _currentNodeItemsTotal = cast(short)n._count; 780 } 781 else 782 { 783 if ( n._count == ItemsPerNode ) 784 { // full node, each token position equals it's number 785 _currentNodeItemPosition = _currentNodeItem; 786 } 787 else 788 { 789 // find next non-zero bit in bitmask 790 auto m = 0xffff_ffff ^ ((1<<(_currentNodeItemPosition+1)) - 1); 791 // debug infof("m: %32.32b", bitswap(m)); 792 // debug infof("b: %32.32b", bitswap(n._bitmap)); 793 // debug infof("r: %32.32b", bitswap(n._bitmap&m)); 794 _currentNodeItemPosition = cast(ubyte)bsf(n._bitmap & m); 795 // debug infof("nodeItem: %s, cp: %d, itemsTotal: %s", _currentNodeItem, _currentNodeItemPosition, _currentNodeItemsTotal); 796 } 797 } 798 } 799 bool empty() 800 { 801 return _empty; 802 } 803 } 804 } 805 806 807 public: 808 auto makeRange(string R)(int start=0, int end=int.max) @safe 809 { 810 static if (R == "mut") 811 { 812 alias _rCounter = _mutRanges_counter; 813 alias _rArray = _mutRanges; 814 alias T = Impl!"mut"; 815 } 816 else static if (R == "const") 817 { 818 alias _rCounter = _constRanges_counter; 819 alias _rArray = _constRanges; 820 alias T = Impl!"const"; 821 } 822 else 823 { 824 static assert(0, "Wrong type"); 825 } 826 // 827 828 829 T** slot; 830 assert(_rCounter < MaxRanges-1); 831 for(auto i=0; i<MaxRanges; i++) 832 { 833 if ( _rArray[i] is null ) 834 { 835 slot = &_rArray[i]; 836 break; 837 } 838 } 839 if ( slot is null ) 840 { 841 assert(0, "Too much active ranges"); 842 } 843 844 _rCounter++; 845 846 auto result = Iterator!T(slot, &this); 847 if ( _count == 0) 848 { 849 // empty list 850 result._impl._empty = true; 851 return result; 852 } 853 854 if ( start < 0 ) 855 { 856 start = _count + start; 857 } 858 if ( end < 0 ) 859 { 860 end = _count + end; 861 } 862 // if end greater than list length - use list length 863 if ( end > _count ) 864 { 865 end = _count; 866 } 867 if ( start == end ) 868 { 869 result._impl._empty = true; 870 return result; 871 } 872 assert(start < _count && end <= _count && start < end); 873 auto node = _first_node; 874 auto item = 0; 875 auto items = end - start; 876 auto nodeItem = 0; 877 while( node !is null && item + node._count <= start ) 878 { 879 item += node._count; 880 node = node._next_node; 881 } 882 nodeItem = start - item; 883 result._impl._currentNode = node; 884 result._impl._currentNodeItem = nodeItem; 885 result._impl._currentNodeItemPosition = node.translate_pos(nodeItem); 886 result._impl._currentNodeItemsTotal = node._count; 887 result._impl._item = start; 888 result._impl._end = end; 889 return result; 890 } 891 alias mutRange = makeRange!("mut"); 892 /++ 893 + Create new const range. Const range preserve it's correctness by 894 + preventing you from any list mutations. 895 + 896 + const range is `value `type` - assignment and initializations create its copy. 897 + 898 + const range can't make warranties on it's correctnes if you make any list mutation. 899 + So, while you have any active const range you can't make any mutation to list. At any 900 + atempt to remove, insert or clear list while const range active you'll get AssertionError. 901 + To make constRange inactive you have to consume it to the end or call `reset` on it. 902 + 903 + Params: 904 + start = start position in list (default value - head of the list) 905 + end = end positions in list (default value - end of the list) 906 + -------------------------------------------------------------------- 907 + UnrolledList!int l; 908 + 909 + foreach(i; 0..50) 910 + { 911 + l.pushBack(i); 912 + } 913 + auto r = l.constRange(); 914 + assert(equal(r, iota(50))); // copy of range created 915 + assertThrown!AssertError(l.clear); // r still active 916 + assertThrown!AssertError(l.remove(0)); // r still active 917 + assertThrown!AssertError(l.pushBack(0)); // r still active 918 + assertThrown!AssertError(l.pushFront(0)); // r still active 919 + assertThrown!AssertError(l.popBack()); // r still active 920 + assertThrown!AssertError(l.popFront()); // r still active 921 + r.reset(); // deactivate r 922 + l.clear(); // it is safe to clear list 923 + ------------------------------------------------------------------- 924 +/ 925 alias constRange = makeRange!"const"; 926 927 this(this) 928 { 929 auto n = _first_node; 930 _first_node = _last_node = null; 931 _count = 0; 932 933 _constRanges_counter = 0; 934 _constRanges = _constRanges.init; 935 936 _mutRanges_counter = 0; 937 _mutRanges = _mutRanges.init; 938 939 _free_list = null; 940 _free_list_count = 0; 941 942 while(n) 943 { 944 auto nn = n._next_node; 945 for(auto i=0; i<ItemsPerNode; i++) 946 { 947 if ( n.test_bit(i) ) 948 { 949 pushBack(n._items[i]); 950 } 951 } 952 n = nn; 953 } 954 } 955 956 ~this() 957 { 958 foreach(r; _constRanges) 959 { 960 if ( r !is null ) 961 { 962 r._empty = true; 963 r._list = null; 964 r._ptr = null; 965 } 966 } 967 foreach(r; _mutRanges) 968 { 969 if ( r !is null ) 970 { 971 r._empty = true; 972 r._list = null; 973 r._ptr = null; 974 } 975 } 976 auto n = _first_node; 977 while(n) 978 { 979 auto nn = n._next_node; 980 deallocNode(n); 981 n = nn; 982 _nodes_counter--; 983 } 984 985 while(_free_list_count) 986 { 987 Node* p = _free_list; 988 _free_list = p._next_node; 989 _free_list_count--; 990 () @trusted { 991 static if ( UseGCRanges!(Allocator,T, GCRangesAllowed) ) { 992 GC.removeRange(&p._items[0]); 993 } 994 dispose(allocator, p); 995 }(); 996 } 997 } 998 999 auto dump() 1000 { 1001 string[] s; 1002 s ~= "<<<"; 1003 s ~= "length: %d".format(_count); 1004 s ~= "nodes: %d".format(_nodes_counter); 1005 s ~= "density: %f".format(_nodes_counter>0?1e0*_count/_nodes_counter/ItemsPerNode:0e0); 1006 s ~= "first_node: %x".format(_first_node); 1007 s ~= "last_node: %x".format(_last_node); 1008 auto n = _first_node; 1009 while(n !is null) 1010 { 1011 s ~= "Page %2.2d nodes, %032b bitmap(swapped)".format(n._count, bitswap(n._bitmap)); 1012 s ~= " 0....o....1....o....2....o....3."; 1013 s ~= "Prev page ptr: %x".format(n._prev_node); 1014 s ~= "Next page ptr: %x".format(n._next_node); 1015 s ~= "%s".format(n._items); 1016 s ~= "---"; 1017 n = n._next_node; 1018 } 1019 s ~= ">>>"; 1020 return s; 1021 } 1022 1023 void clear() 1024 { 1025 assert(_constRanges_counter == 0, "You can't call mutating methods while constRange active. Use stableRange"); 1026 if (_mutRanges_counter) 1027 sendnotify(Sig.CLEAR, 0, null, 0); 1028 auto n = _first_node; 1029 while(n) 1030 { 1031 auto nn = n._next_node; 1032 deallocNode(n); 1033 _nodes_counter--; 1034 n = nn; 1035 } 1036 _count = 0; 1037 _first_node = _last_node = null; 1038 } 1039 1040 private auto _node_and_index(size_t i) 1041 in(i<_count) 1042 out(r; r.node !is null && r.index < ItemsPerNode) 1043 do 1044 { 1045 Node *n; 1046 // select iteration direcion 1047 if ( i > ItemsPerNode && i > _count /2 ) 1048 { 1049 // iterate from end to beg 1050 n = _last_node; 1051 auto b = _count; 1052 while ( b - n._count > i ) 1053 { 1054 b -= n._count; 1055 n = n._prev_node; 1056 } 1057 i = i - b + n._count; 1058 } 1059 else 1060 { 1061 // iterate from beg to end 1062 n = _first_node; 1063 while(i >= n._count) 1064 { 1065 i -= n._count; 1066 n = n._next_node; 1067 } 1068 } 1069 return Tuple!(Node*, "node", int, "index")(n, cast(int)i); 1070 } 1071 /++ 1072 Get item at some position. 1073 1074 To be @nogc it do not throw, but return tuple with bool `ok`member. 1075 1076 Params: 1077 i = position 1078 Returns: 1079 tuple with succes indicator and value 1080 ------------------------------------- 1081 UnrolledList!int l; 1082 foreach(i; 0..50) 1083 { 1084 l.pushBack(i); 1085 } 1086 auto v = l.get(25); 1087 assert(v.ok); 1088 assert(v.value == 25); 1089 ------------------------------------- 1090 +/ 1091 auto get(size_t i) 1092 { 1093 if (_count == 0 || i >= _count ) 1094 { 1095 return Tuple!(bool, "ok", StoredT, "value")(false, T.init); 1096 } 1097 auto ni = _node_and_index(i); 1098 auto n = ni.node; 1099 auto pos = n.translate_pos(ni.index); 1100 assert(n.test_bit(pos)); 1101 return Tuple!(bool, "ok", StoredT, "value")(true, n._items[pos]); 1102 } 1103 // O(N) 1104 auto opIndex(size_t i) 1105 { 1106 auto v = get(i); 1107 if ( !v.ok ) 1108 { 1109 throw new RangeError("index %d out of range".format(i)); 1110 } 1111 return v.value; 1112 } 1113 // O(N) 1114 void opAssign(ref typeof(this) other) 1115 { 1116 if (other is this) 1117 { 1118 return; 1119 } 1120 clear(); 1121 auto n = other._first_node; 1122 while(n) 1123 { 1124 auto nn = n._next_node; 1125 for(auto i=0; i<ItemsPerNode; i++) 1126 { 1127 if ( n.test_bit(i) ) 1128 { 1129 pushBack(n._items[i]); 1130 } 1131 } 1132 n = nn; 1133 } 1134 } 1135 // O(N) 1136 void opIndexAssign(V)(V v, size_t i) 1137 { 1138 if (_count == 0 || i >= _count ) 1139 { 1140 throw new RangeError("index %d out of range".format(i)); 1141 } 1142 auto ni = _node_and_index(i); 1143 auto n = ni.node; 1144 auto pos = n.translate_pos(ni.index); 1145 assert(n.test_bit(pos)); 1146 n._items[pos] = v; 1147 } 1148 // O(1) 1149 bool empty() 1150 { 1151 return _count == 0; 1152 } 1153 // O(1) 1154 auto length() pure @safe @nogc nothrow 1155 { 1156 return _count; 1157 } 1158 // O(1) 1159 auto front() 1160 { 1161 assert(_count > 0, "Attempting to fetch the front of an empty list"); 1162 auto n = _first_node; 1163 while(n && n._count == 0) 1164 { 1165 n = n._next_node; 1166 } 1167 auto p = bsf(n._bitmap); 1168 return n._items[p]; 1169 } 1170 /++ 1171 + Get last item. O(1) 1172 + 1173 + Returns: last item. 1174 + Throws: AssertError when list is empty. 1175 +/ 1176 auto back() 1177 { 1178 assert(_count > 0, "Attempting to fetch the front of an empty list"); 1179 auto n = _last_node; 1180 while(n && n._count == 0) 1181 { 1182 n = n._prev_node; 1183 } 1184 auto p = bsr(n._bitmap); 1185 return n._items[p]; 1186 } 1187 /// 1188 /// send notifications to mutrange's 1189 /// Params: 1190 /// s= - Sig type 1191 /// item= - number of the item in the list, where we place new item(this would be its number). 1192 /// n= - current node (where we hope to place new item) 1193 /// nodeItem= - number of the new item for this node 1194 // 1195 private void sendnotify(Sig s, int item, Node* n, int nodeItem) pure @nogc @safe nothrow 1196 { 1197 auto mcs = _mutRanges_counter; 1198 for(int mr; mcs>0 && mr < MaxRanges; mr++) 1199 { 1200 if (_mutRanges[mr] !is null) 1201 { 1202 _mutRanges[mr].signal(s, item, n, nodeItem); 1203 mcs--; 1204 } 1205 } 1206 } 1207 /++ 1208 + Append item to the list. O(1) 1209 + 1210 + Throws: AssertError if any const range is registered. 1211 +/ 1212 void pushBack(V)(V v) 1213 { 1214 assert(_constRanges_counter == 0, "You can't mutate list while there are active const ranges"); 1215 if (_mutRanges_counter>0) 1216 { 1217 sendnotify(Sig.INSERT, _count, _last_node, _last_node?_last_node._count:-1); 1218 } 1219 _doRealPushBack(v); 1220 } 1221 /++ 1222 + Prepend list with item v. O(1) 1223 + 1224 + Throws: AssertError if any const range is registered. 1225 +/ 1226 void pushFront(V)(V v) 1227 { 1228 assert(_constRanges_counter == 0, "You can't mutate list while there are active const ranges"); 1229 if (_mutRanges_counter) 1230 sendnotify(Sig.INSERT, 0, _first_node, 0); 1231 _doRealInsert(_first_node, 0, v); 1232 } 1233 /++ 1234 + Pop first item from the list. O(1) 1235 + 1236 + No action if list is empty. 1237 + 1238 + Throws: AssertError if any const range is registered. 1239 +/ 1240 void popFront() 1241 { 1242 assert(_constRanges_counter == 0, "You can't mutate list while there are active const ranges"); 1243 if ( _count == 0 ) 1244 { 1245 return; 1246 } 1247 assert(_first_node); 1248 auto node = _first_node; 1249 while(node._count == 0) 1250 { 1251 node = node._next_node; 1252 } 1253 if (_mutRanges_counter>0) 1254 sendnotify(Sig.REMOVE, 0, node, 0); 1255 _count--; 1256 auto pos = bsf(node._bitmap); 1257 node._count--; 1258 node.clear_bit(pos); 1259 node._items[pos] = T.init; 1260 if (_first_node._count == 0) 1261 { 1262 // release this page 1263 auto n = _first_node; 1264 _first_node = n._next_node; 1265 if ( _first_node is null ) 1266 { 1267 _last_node = null; 1268 } 1269 else 1270 { 1271 _first_node._prev_node = null; 1272 } 1273 deallocNode(n); 1274 _nodes_counter--; 1275 } 1276 } 1277 /++ 1278 + Pop last item from the list. O(1) 1279 + 1280 + No action if list is empty. 1281 + 1282 + Throws: AssertError if any const range is registered. 1283 +/ 1284 void popBack() 1285 { 1286 assert(_constRanges_counter == 0, "You can't mutate list while there are active const ranges"); 1287 if ( _count == 0 ) 1288 { 1289 return; 1290 } 1291 if (_mutRanges_counter>0) 1292 sendnotify(Sig.REMOVE, _count - 1, _last_node, _last_node._count - 1); 1293 _count--; 1294 auto node = _last_node; 1295 while(node && node._count == 0) 1296 { 1297 node = node._prev_node; 1298 } 1299 auto pos = bsr(node._bitmap); 1300 node._count--; 1301 assert(node._count>=0 && node._count < ItemsPerNode); 1302 node.clear_bit(pos); 1303 node._items[pos] = T.init; 1304 if (_last_node._count == 0 && _mutRanges_counter == 0) 1305 { 1306 // release this node 1307 auto n = _last_node; 1308 _last_node._next_node = null; 1309 _last_node = n._prev_node; 1310 if ( _last_node is null ) 1311 { 1312 _first_node = null; 1313 } 1314 else 1315 { 1316 _last_node._next_node = null; 1317 } 1318 deallocNode(n); 1319 _nodes_counter--; 1320 } 1321 } 1322 /++ 1323 + Remove item from the list by item index. O(N) 1324 + 1325 + No action if list is empty. 1326 + Returns: True if item were removed. 1327 + Throws: AssertError if any const range is registered. 1328 +/ 1329 bool remove(int i) 1330 { 1331 assert(_constRanges_counter == 0, "You can't mutate list while there are active const ranges"); 1332 if ( i >= _count ) 1333 { 1334 return false; 1335 } 1336 if ( i == 0 ) 1337 { 1338 popFront(); 1339 return true; 1340 } 1341 if ( i == _count - 1) 1342 { 1343 popBack(); 1344 return true; 1345 } 1346 auto ni = _node_and_index(i); 1347 auto index = ni.index; 1348 auto node = ni.node; 1349 auto pos = node.translate_pos(index); 1350 int mcs = _mutRanges_counter; 1351 for(int mr; mcs>0 && mr < MaxRanges; mr++) 1352 { 1353 if (_mutRanges[mr] !is null) 1354 { 1355 _mutRanges[mr].signal(Sig.REMOVE, i, node, index); 1356 mcs--; 1357 } 1358 } 1359 _count--; 1360 node._count--; 1361 node.clear_bit(pos); 1362 node._items[pos] = T.init; 1363 return true; 1364 } 1365 pragma(inline, true): 1366 private void _doRealPushBack(V)(V v) 1367 { 1368 int pos; 1369 Node* node = _last_node; 1370 while( node && node._count == 0 && node._prev_node ) 1371 { 1372 node = node._prev_node; 1373 } 1374 1375 if ( node && !node.test_bit(ItemsPerNode-1)) 1376 { 1377 pos = node._bitmap ? bsr(node._bitmap) + 1 : 0; 1378 } 1379 else 1380 { 1381 node = makeNode(); 1382 if ( !_last_node ) 1383 { 1384 assert(!_first_node); 1385 _first_node = _last_node = node; 1386 } 1387 else 1388 { 1389 node._prev_node = _last_node; 1390 _last_node._next_node = node; 1391 _last_node = node; 1392 } 1393 _nodes_counter++; 1394 pos = 0; 1395 } 1396 node._count++; 1397 // take most significant free bit 1398 node.mark_bit(pos); 1399 node._items[pos] = v; 1400 _count++; 1401 } 1402 private bool _doRealInsert(V)(Node* node, int index, V v) 1403 { 1404 int pos; 1405 if (node is null) 1406 { 1407 assert(_first_node is null && _last_node is null, "head and tail must be null"); 1408 node = makeNode(); 1409 pos = NewItemPosition; 1410 _first_node = _last_node = node; 1411 _nodes_counter++; 1412 } 1413 else 1414 { 1415 pos = node.translate_pos(index); 1416 } 1417 1418 int lo_mask = node._lo_mask(pos); 1419 int hi_mask = node._hi_mask(pos); 1420 1421 int lo_shift = lo_mask != 0 ? bsf(lo_mask ^ uint.max) : 1422 pos == 0 ? -1 : 0; 1423 int hi_shift = hi_mask == 0 ? uint.max : bsf(hi_mask ^ uint.max); 1424 auto lo_overflow = lo_shift < hi_shift && lo_shift >= pos; 1425 auto hi_overflow = hi_shift <= lo_shift && pos + hi_shift >= ItemsPerNode; 1426 1427 // debug infof("itemPos: %s", pos); 1428 // debug infof("index: %s", index); 1429 // debug infof("bitmap %32.32b", node._bitmap); 1430 // debug infof("lomask %32.32b", lo_mask); 1431 // debug infof("himask %32.32b", hi_mask); 1432 // debug infof("lo_shift: %d, hi shift: %d", lo_shift, hi_shift); 1433 // debug infof("lo_over: %s, hi overfl: %s", lo_overflow, hi_overflow); 1434 if ( lo_overflow ) 1435 { 1436 debug(ikodcontainers) tracef("low overflow"); 1437 if ( node._prev_node 1438 && node._prev_node.count_free_high_bits() > 0 ) 1439 { 1440 Node* n = node._prev_node; 1441 debug(ikodcontainers) tracef("low overflow to existent node with %s free high bits", n.count_free_high_bits()); 1442 // find free bit _0000100000^ _111v1111^ 1443 int fp = n._bitmap ? bsf(bitswap(n._bitmap)) : NewItemPosition; 1444 debug(ikodcontainers) tracef("overflow to %s", ItemsPerNode - fp); 1445 int p = ItemsPerNode - fp; 1446 n._count++; 1447 n.mark_bit(p); 1448 n._items[p] = node._items[0]; 1449 // now do shift left for lo_shift-1 1450 for(int i=0;i < lo_shift - 1; i++) 1451 { 1452 node._items[i] = node._items[i+1]; 1453 } 1454 node._items[index-1] = v; 1455 _count++; 1456 return true; 1457 } 1458 else 1459 { 1460 debug(ikodcontainers) tracef("low overflow to new node"); 1461 auto new_node = makeNode(); 1462 auto new_p = NewItemPosition; 1463 new_node.mark_bit(new_p); 1464 new_node._items[new_p] = node._items[0]; 1465 new_node._count = 1; 1466 for(int i=0;i < lo_shift - 1; i++) 1467 { 1468 node._items[i] = node._items[i+1]; 1469 } 1470 node._items[index-1] = v; 1471 if ( _first_node == node ) 1472 { 1473 _first_node = new_node; 1474 } 1475 else 1476 { 1477 node._prev_node._next_node = new_node; 1478 new_node._prev_node = node._prev_node; 1479 } 1480 new_node._next_node = node; 1481 node._prev_node = new_node; 1482 _count++; 1483 _nodes_counter++; 1484 return true; 1485 } 1486 } 1487 if ( hi_overflow ) 1488 { 1489 debug(ikodcontainers) tracef("high overflow"); 1490 if (node._next_node && node._next_node.count_free_low_bits() > 0) 1491 { 1492 debug(ikodcontainers) tracef("high overflow to next existent node"); 1493 auto next_node = node._next_node; 1494 auto next_node_pos = next_node._bitmap ? bsf(next_node._bitmap)-1 : NewItemPosition; 1495 next_node.mark_bit(next_node_pos); 1496 next_node._count++; 1497 next_node._items[next_node_pos] = node._items[ItemsPerNode-1]; 1498 for(auto s=hi_shift; s>0; s--) 1499 { 1500 node._items[pos+s-1] = node._items[pos+s-2]; 1501 } 1502 node._items[pos] = v; 1503 _count++; 1504 return true; 1505 } 1506 else 1507 { 1508 debug(ikodcontainers) tracef("high overflow to new node"); 1509 auto new_node = makeNode(); 1510 auto new_p = NewItemPosition; 1511 new_node.mark_bit(new_p); 1512 new_node._items[new_p] = node._items[ItemsPerNode-1]; 1513 new_node._count++; 1514 for(auto s=hi_shift; s>0; s--) 1515 { 1516 node._items[pos+s-1] = node._items[pos+s-2]; 1517 } 1518 node._items[pos] = v; 1519 // link right 1520 if ( _last_node == node) 1521 { 1522 _last_node = new_node; 1523 } 1524 else 1525 { 1526 node._next_node._prev_node = new_node; 1527 new_node._next_node = node._next_node; 1528 } 1529 new_node._prev_node = node; 1530 node._next_node = new_node; 1531 _count++; 1532 _nodes_counter++; 1533 return true; 1534 } 1535 } 1536 if ( lo_shift == 0 ) 1537 { 1538 // we have free space to insert 1539 assert(!node.test_bit(pos-1)); 1540 node._count++; 1541 assert(node._count <= ItemsPerNode); 1542 node._items[pos-1] = v; 1543 node.mark_bit(pos-1); 1544 _count++; 1545 return true; 1546 } 1547 if ( lo_shift == -1 ) 1548 { 1549 // +-- insert here 1550 // v 1551 // XXXXXXXX 1552 if ( node._prev_node ) 1553 { 1554 immutable fhb = node._prev_node.count_free_high_bits(); 1555 if ( fhb>0 ) 1556 { 1557 // we can store it in prev node 1558 node = node._prev_node; 1559 auto new_p = ItemsPerNode - fhb; 1560 assert(!node.test_bit(new_p)); 1561 node.mark_bit(new_p); 1562 node._items[new_p] = v; 1563 node._count++; 1564 _count++; 1565 return true; 1566 } 1567 } 1568 auto new_node = makeNode(); 1569 auto new_p = NewItemPosition; 1570 if ( _first_node == node ) 1571 { 1572 _first_node = new_node; 1573 } 1574 else 1575 { 1576 node._prev_node._next_node = new_node; 1577 new_node._prev_node = node._prev_node; 1578 } 1579 new_node._next_node = node; 1580 node._prev_node = new_node; 1581 new_node._count = 1; 1582 new_node._items[new_p] = v; 1583 new_node.mark_bit(new_p); 1584 _count++; 1585 _nodes_counter++; 1586 return true; 1587 } 1588 if ( lo_shift < hi_shift ) 1589 { 1590 assert(!node.full); 1591 // shift to low items 1592 auto new_pos = pos-lo_shift - 1; 1593 for(auto s=0; s<lo_shift+1; s++) 1594 { 1595 node._items[new_pos+s] = node._items[new_pos+s+1]; 1596 } 1597 node.mark_bit(new_pos); 1598 node._count++; 1599 assert(node._count <= ItemsPerNode); 1600 node._items[pos-1] = v; 1601 // node.mark_bit(pos); 1602 _count++; 1603 return true; 1604 } 1605 else 1606 { 1607 assert(!node.full); 1608 // shift to hight items 1609 auto new_pos = pos+hi_shift; 1610 for(auto s=hi_shift; s>0; s--) 1611 { 1612 node._items[pos+s] = node._items[pos+s-1]; 1613 } 1614 node.mark_bit(new_pos); 1615 node._count++; 1616 assert(node._count <= ItemsPerNode); 1617 node._items[pos] = v; 1618 // node.mark_bit(pos); 1619 _count++; 1620 return true; 1621 } 1622 assert(0); 1623 } 1624 /++ 1625 + Insert item at position i. O(N) 1626 + 1627 + Params: 1628 + v = value to insert 1629 + i = position for this value 1630 + 1631 + Returns: True if item were inserted (false if index is > list.length+1) 1632 + Throws: AssertError if any const range is registered. 1633 +/ 1634 bool insert(V)(int i, V v) 1635 { 1636 assert(_constRanges_counter == 0, "You can't mutate list while there are active const ranges"); 1637 debug(ikodcontainers) tracef("insert %s at %s", v, i); 1638 if ( i > _count ) 1639 { 1640 return false; 1641 } 1642 if ( i == 0 ) 1643 { 1644 pushFront(v); 1645 return true; 1646 } 1647 if ( i == _count ) 1648 { 1649 pushBack(v); 1650 return true; 1651 } 1652 auto ni = _node_and_index(i); 1653 int index = ni.index; 1654 Node* node = ni.node; 1655 1656 if ( _mutRanges_counter>0) 1657 sendnotify(Sig.INSERT, i, node, index); 1658 1659 return _doRealInsert(node, index, v); 1660 } 1661 } 1662 @("ul0") 1663 unittest 1664 { 1665 UnrolledList!int list; 1666 list.pushFront(1); 1667 assert(list.length == 1); 1668 assert(list.front == 1); 1669 assert(list.back == 1); 1670 list.pushFront(0); 1671 assert(list.length == 2); 1672 assert(list.front == 0); 1673 assert(list.back == 1); 1674 list.pushBack(2); 1675 assert(list.length == 3); 1676 assert(list.front == 0); 1677 assert(list.back == 2); 1678 list.pushBack(3); 1679 assert(list.length == 4); 1680 assert(list.front == 0); 1681 assert(list.back == 3); 1682 1683 list.popFront(); 1684 assert(list.length == 3); 1685 assert(list.front == 1); 1686 assert(list.back == 3); 1687 list.popFront(); 1688 assert(list.length == 2); 1689 assert(list.front == 2); 1690 assert(list.back == 3); 1691 list.popFront(); 1692 assert(list.length == 1); 1693 assert(list.front == 3); 1694 assert(list.back == 3); 1695 list.popFront(); 1696 assert(list.empty); 1697 foreach(int i; 0..1000) 1698 { 1699 list.pushBack(i); 1700 } 1701 assert(list.length == 1000); 1702 assert(list.front == 0, "<%s>".format(list.front)); 1703 assert(list.back == 999, "<%s>".format(list.back)); 1704 foreach(int i; 0..1000) 1705 { 1706 assert(list[i] == i); 1707 } 1708 list.popFront(); 1709 foreach(int i; 1..1000) 1710 { 1711 assert(list[i-1] == i); 1712 } 1713 foreach(int i; 1..1000) 1714 { 1715 list.popBack(); 1716 } 1717 assert(list.length == 0); 1718 // fill it again 1719 foreach(int i; 0..1000) 1720 { 1721 list.pushBack(i); 1722 } 1723 list.remove(100); 1724 assert(list[100] == 101); 1725 foreach(_;0..list.ItemsPerNode) 1726 { 1727 list.remove(0); 1728 } 1729 assert(list[0] == list.ItemsPerNode); 1730 assert(list.length == 1000 - list.ItemsPerNode - 1); 1731 // test clear 1732 list.clear(); 1733 assert(list.length == 0); 1734 // test inserts 1735 list.insert(0, 1); // |1| | 1736 list.insert(0, 0); // |0|1| 1737 assert(list.length == 2); 1738 assert(list[0] == 0); 1739 assert(list[1] == 1); 1740 list.clear(); 1741 foreach(int i; 0..list.ItemsPerNode) 1742 { 1743 list.pushBack(i); 1744 } 1745 assert(list.length == list.ItemsPerNode); // |0|1|...|14|15| 1746 list.remove(14); // |0|1|...|__|15| 1747 assert(list[14] == 15); 1748 list.insert(14,14); 1749 assert(list[14] == 14); // |0|1|...|14|15| 1750 list.popBack(); // |0|1|...|14|__| 1751 list[14] = 15; 1752 assert(list[14] == 15); // |0|1|...|15|__| 1753 list.insert(14,14); 1754 assert(list[14] == 14); // |0|1|...|14|15| 1755 assert(list[15] == 15); // |0|1|...|14|15| 1756 assert(list.length == list.ItemsPerNode); 1757 list.insert(2, 16); 1758 assert(list[2] == 16); 1759 assert(list.length == list.ItemsPerNode+1); 1760 assert(list.back == list.ItemsPerNode-2); 1761 list.insert(5, 17); 1762 list.insert(3,55); 1763 list.insert(17, 88); 1764 list.insert(15, 99); 1765 assert(list[15] == 99); 1766 } 1767 1768 @("ul1") 1769 @safe unittest 1770 { 1771 UnrolledList!int l; 1772 assert(l.length == 0); 1773 l.pushBack(0); 1774 assert(l.length == 1); 1775 assert(l.front == 0); 1776 assert(l.back == 0); 1777 l.pushBack(1); 1778 assert(l.length == 2); 1779 assert(l.front == 0); 1780 assert(l.back == 1); 1781 l.pushFront(2); 1782 assert(l.length == 3); 1783 assert(l.front == 2); 1784 assert(l.back == 1); 1785 l.pushFront(3); 1786 assert(l.length == 4); 1787 assert(l.front == 3); 1788 assert(l.back == 1); 1789 l.popBack(); 1790 assert(l.length == 3); 1791 assert(l.front == 3); 1792 assert(l.back == 0); 1793 l.popBack(); 1794 assert(l.length == 2); 1795 assert(l.front == 3); 1796 assert(l.back == 2); 1797 } 1798 @("ul2") 1799 @safe @nogc unittest 1800 { 1801 UnrolledList!int l0, l1; 1802 foreach(i;0..1_000) 1803 { 1804 l0.pushBack(i); 1805 } 1806 l1 = l0; 1807 foreach(i;0..1_000) 1808 { 1809 immutable v = l1.get(i); 1810 assert(v.ok); 1811 assert(v.value == i); 1812 } 1813 l1 = l0; 1814 foreach(i;0..1_000) 1815 { 1816 immutable v = l1.get(i); 1817 assert(v.ok); 1818 assert(v.value == i); 1819 } 1820 auto l2 = l1; 1821 foreach(i;0..1_000) 1822 { 1823 immutable v = l2.get(i); 1824 assert(v.ok); 1825 assert(v.value == i); 1826 } 1827 } 1828 1829 @("ul2") 1830 @safe @nogc unittest 1831 { 1832 UnrolledList!int l; 1833 foreach(i;0..1_000) 1834 { 1835 l.pushBack(i); 1836 } 1837 foreach(i;0..1_000) 1838 { 1839 immutable v = l.get(i); 1840 assert(v.ok); 1841 assert(v.value == i); 1842 } 1843 } 1844 1845 @("ul3") 1846 unittest 1847 { 1848 import std.exception; 1849 UnrolledList!int l; 1850 assertThrown!RangeError(l[0]); 1851 foreach(i; 0..1_000) 1852 { 1853 l.pushBack(i); 1854 } 1855 assertThrown!RangeError(l[1000]); 1856 foreach(i; 0..1_000) 1857 { 1858 l[i] = i * 2; 1859 } 1860 foreach(i;0..1_000) 1861 { 1862 assert(l[i] == i * 2); 1863 } 1864 } 1865 @("ul4") 1866 @safe unittest 1867 { 1868 UnrolledList!int l; 1869 foreach(i;0..2*l.ItemsPerNode) 1870 { 1871 l.pushBack(i); 1872 } 1873 // ↓ ins B 1874 // XXX....XXA->XXX....XXX 1875 l.insert(l.ItemsPerNode-1, 1000); 1876 // XXX....XXB->OOO..A..OOO->XXX....XXX 1877 assert(l[l.ItemsPerNode - 1] == 1000); 1878 assert(l.length == l.ItemsPerNode*2 + 1); 1879 } 1880 @("ul5") 1881 @safe unittest 1882 { 1883 UnrolledList!int l; 1884 foreach(i;0..2*l.ItemsPerNode) 1885 { 1886 l.pushBack(i); 1887 } 1888 l.remove(l.ItemsPerNode); 1889 // ins B↓ 1890 // XXX....XXA -> OXX....XXX 1891 l.insert(l.ItemsPerNode - 1, 1000); 1892 // 1893 // XXX....XXB -> AXX....XXX 1894 assert(l[l.ItemsPerNode - 1] == 1000); 1895 assert(l.length == 2 * l.ItemsPerNode); 1896 } 1897 @("ul6") 1898 @safe unittest 1899 { 1900 UnrolledList!int l; 1901 foreach(i;0..2*l.ItemsPerNode) 1902 { 1903 l.pushBack(i); 1904 } 1905 // ins B↓ 1906 // XXX....XXX -> XXX....XXX 1907 l.insert(l.ItemsPerNode, 1000); 1908 // XXX....XXX->OOO..B..OOO->XXX....XXX 1909 assert(l[l.ItemsPerNode] == 1000); 1910 assert(l.length == 2 * l.ItemsPerNode + 1); 1911 } 1912 1913 @("ul7") 1914 @safe unittest 1915 { 1916 UnrolledList!int l; 1917 foreach(i;0..l.ItemsPerNode) 1918 { 1919 l.pushBack(i); 1920 } 1921 l.remove(2); 1922 // B↓ 1923 // XXOX..XXX 1924 l.insert(2, 1000); 1925 // XXBX..XXX 1926 assert(l[2] == 1000); 1927 assert(l.length == l.ItemsPerNode); 1928 } 1929 1930 @("ul8") 1931 @safe unittest 1932 { 1933 UnrolledList!int l; 1934 foreach(i;0..l.ItemsPerNode) 1935 { 1936 l.pushBack(i); 1937 } 1938 l.remove(2); 1939 // B↓ 1940 // XAOX..XXX 1941 l.insert(1, 1000); 1942 // XBAX..XXX 1943 assert(l[1] == 1000); 1944 assert(l.length == l.ItemsPerNode); 1945 } 1946 1947 @("ul9") 1948 @safe unittest 1949 { 1950 UnrolledList!int l; 1951 foreach(i;0..l.ItemsPerNode) 1952 { 1953 l.pushBack(i); 1954 } 1955 l.remove(l.ItemsPerNode-2); 1956 l.remove(0); 1957 l.remove(1); 1958 // B↓ 1959 // OXOXXX..XXO 1960 l.insert(2, 1000); 1961 // XBAX..XXX 1962 l.insert(27, 2000); 1963 assert(l[27] == 2000); 1964 assert(l.length == l.ItemsPerNode-1); 1965 } 1966 @("ul10") 1967 @safe unittest 1968 { 1969 UnrolledList!int l; 1970 foreach(i;0..l.ItemsPerNode) 1971 { 1972 l.pushBack(i); 1973 } 1974 l.remove(0); 1975 l.insert(30,1000); 1976 assert(l[0]==1); 1977 assert(l[30] == 1000); 1978 } 1979 1980 @("mutIterator1") 1981 unittest 1982 { 1983 import std.stdio; 1984 import std.range; 1985 import std.exception; 1986 import std.math; 1987 1988 UnrolledList!int l; 1989 1990 foreach(i; 0..50) 1991 { 1992 l.pushBack(i); 1993 } 1994 auto r = l.mutRange(1, -1); 1995 foreach(v; r) 1996 { 1997 assert(v>=0); 1998 } 1999 r = l.mutRange(); 2000 while(!r.empty) 2001 { 2002 auto v = r.front; 2003 if ( v % 2 ) 2004 { 2005 r.remove(); 2006 } 2007 else 2008 { 2009 r.popFront; 2010 } 2011 } 2012 assert(equal(l.constRange,iota(0, 50, 2))); 2013 l.clear; 2014 // 2015 // Build Eratosphenes seed, compare with correct list and clear it 2016 // 2017 enum limit = 100_500; 2018 uint[] sieve(in uint limit) nothrow @safe { 2019 // https://rosettacode.org/wiki/Sieve_of_Eratosthenes#Simpler_Version 2020 if (limit < 2) 2021 return []; 2022 auto composite = new bool[limit]; 2023 2024 foreach (immutable uint n; 2 .. cast(uint)(limit ^^ 0.5) + 1) 2025 if (!composite[n]) 2026 for (uint k = n * n; k < limit; k += n) 2027 composite[k] = true; 2028 2029 return iota(2, limit).filter!(i => !composite[i]).array; 2030 } 2031 foreach(i; 2..limit) 2032 { 2033 l.pushBack(i); 2034 } 2035 foreach(index,value; l.mutRange(0, cast(int)sqrt(real(limit))+1).enumerate) 2036 { 2037 for(auto r1 = l.mutRange(cast(int)index); !r1.empty;) 2038 { 2039 if (r1.front > value && r1.front % value == 0) 2040 { 2041 r1.remove; 2042 } 2043 else 2044 { 2045 r1.popFront; 2046 } 2047 } 2048 } 2049 // foreach(s; l.dump) 2050 // { 2051 // info(s); 2052 // } 2053 assert(equal(l.constRange, sieve(limit))); 2054 l.popFront; 2055 l.popBack; 2056 r = l.mutRange(); 2057 while(!r.empty) 2058 { 2059 r.remove(); 2060 } 2061 assert(r.empty); 2062 assert(r.count == 0); 2063 assert(l.length == 0); 2064 // 2065 // test popFront/popBack handling by mutRange 2066 foreach(i; 0..50) 2067 { 2068 l.pushBack(i); 2069 } 2070 // foreach(s; l.dump) 2071 // { 2072 // info(s); 2073 // } 2074 r = l.mutRange(); 2075 while(!l.empty) 2076 { 2077 l.popFront; 2078 l.popBack; 2079 assertThrown!AssertError(r.front); // you tried to access deleted item 2080 r.popFront; 2081 assert(equal(r, l.constRange)); 2082 } 2083 } 2084 @("mutIterator2") 2085 unittest 2086 { 2087 import std.stdio; 2088 import std.range; 2089 import std.exception; 2090 2091 auto l = UnrolledList!int(); 2092 foreach(i; iota(1, 50, 2)) 2093 { 2094 l.pushBack(i); 2095 } 2096 assert(equal(l.constRange(0, 5), [1,3,5,7,9])); 2097 auto r0 = l.mutRange(); 2098 auto r1 = r0; 2099 // foreach(s; l.dump) 2100 // { 2101 // info(s); 2102 // } 2103 while(!r0.empty) 2104 { 2105 // infof("---insert %s", r0.front-1); 2106 r0.insert(r0.front - 1); 2107 r0.popFront; 2108 } 2109 assert(equal(l.constRange(0, 5), [0,1,2,3,4])); 2110 assert(equal(l.constRange(), iota(50))); 2111 // foreach(s; l.dump) 2112 // { 2113 // info(s); 2114 // } 2115 // while(!r1.empty) 2116 // { 2117 // writeln(r1.front); 2118 // r1.popFront; 2119 // } 2120 assert(equal(r1, iota(1,50))); 2121 assert(equal(l.constRange, iota(50))); 2122 r0 = l.mutRange(); 2123 while(!r0.empty) 2124 { 2125 // infof("front %s", r0.front); 2126 if ( r0.front % 2 == 0) 2127 { 2128 // infof("remove %s", r0.front); 2129 r0.remove(); 2130 } 2131 else 2132 { 2133 r0.popFront; 2134 } 2135 // foreach(s; l.dump) 2136 // { 2137 // info(s); 2138 // } 2139 } 2140 assert(equal(r1, iota(1, 50, 2))); 2141 r0 = l.mutRange(); 2142 int x = 0; 2143 while(!r0.empty) 2144 { 2145 // infof("---insert %s", x); 2146 r0.insert(x); 2147 x += 2; 2148 r0.popFront; 2149 // foreach(s; l.dump) 2150 // { 2151 // info(s); 2152 // } 2153 } 2154 assert(equal(l.constRange(), iota(50))); 2155 // while(!r1.empty) 2156 // { 2157 // writeln(r1.front); 2158 // r1.popFront; 2159 // } 2160 assert(equal(r1, iota(1, 50))); 2161 } 2162 @("mutIterator3") 2163 unittest 2164 { 2165 import std.stdio; 2166 import std.range; 2167 import std.exception; 2168 import std.random; 2169 auto rnd = Random(19); 2170 2171 auto l = UnrolledList!int(); 2172 while(l.length < 5) 2173 { 2174 int v = uniform(0, 10000, rnd); 2175 auto i = l.mutRange(); 2176 while(!i.empty && i.front > v) 2177 { 2178 i.popFront; 2179 } 2180 i.insert(v); 2181 } 2182 } 2183 2184 @("constIterator") 2185 unittest 2186 { 2187 import std.range; 2188 import std.exception; 2189 import std.algorithm; 2190 import std.stdio; 2191 2192 UnrolledList!int l; 2193 2194 foreach(i; 0..50) 2195 { 2196 l.pushBack(i); 2197 } 2198 auto r = l.constRange(); 2199 assert(equal(r, iota(50))); 2200 assertThrown!AssertError(l.clear); // r still active 2201 assertThrown!AssertError(l.remove(0)); // r still active 2202 assertThrown!AssertError(l.pushBack(0)); // r still active 2203 assertThrown!AssertError(l.pushFront(0)); // r still active 2204 assertThrown!AssertError(l.popBack()); // r still active 2205 assertThrown!AssertError(l.popFront()); // r still active 2206 r.reset(); // deactivate r 2207 l.clear(); 2208 foreach(i; 0..50) 2209 { 2210 l.pushBack(i); 2211 } 2212 r = l.constRange(); 2213 auto r1 = r; 2214 r.reset(); 2215 assert(equal(r1.take(10), iota(10))); // still can use r1 2216 r1 = l.constRange(); 2217 r1 = r1; 2218 r.reset(); 2219 assert(l._constRanges_counter == 1); // r1 only 2220 assert(equal(r1, iota(50))); 2221 // test negative indexing 2222 assert(equal(l.constRange(25), iota(25,50))); 2223 assert(l.constRange(-3, -3).count == 0); 2224 assertThrown!AssertError(l.constRange(0, -10000)); 2225 assert(l._constRanges_counter == 1); // r1 only, temp ranges unregistered 2226 2227 r = l.constRange(); 2228 assert(l._constRanges_counter == 2); // r and r1 2229 foreach(i, v; r.enumerate) 2230 { 2231 r1 = l.constRange(cast(int)i, 50); 2232 assert(equal(r1, iota(i, 50))); 2233 } 2234 r1.reset(); 2235 r.reset(); 2236 assert(l._constRanges_counter == 0); // we cleared everything 2237 2238 // test unregister on list destruction 2239 { 2240 UnrolledList!int l1; 2241 foreach(i; 0..50) 2242 { 2243 l1.pushBack(i); 2244 } 2245 r1 = l1.constRange(); 2246 assert(r1.count == 50); 2247 foreach(i,v; r1.enumerate) 2248 { 2249 auto r2 = l1.constRange(cast(int)i); 2250 assert(equal(r2, iota(i, 50))); 2251 } 2252 assert(r1.count == 50); 2253 } 2254 assert(r1.count == 0); // lost container 2255 r = l.constRange(); 2256 assertThrown!AssertError(l.clear); 2257 while(!r.empty) 2258 { 2259 r.popFront; 2260 } 2261 l.clear; 2262 2263 foreach(i; 0..50) 2264 { 2265 l.pushBack(i); 2266 } 2267 r = l.constRange(); 2268 assertThrown!AssertError(l.clear); 2269 foreach(i; r) 2270 { 2271 assert(i>=0); 2272 } 2273 // iterator consumed by opApply 2274 l.clear; 2275 } 2276 @("classes") 2277 @safe 2278 unittest 2279 { 2280 import std.range; 2281 class C 2282 { 2283 int c; 2284 this(int i) 2285 { 2286 c = i; 2287 } 2288 } 2289 UnrolledList!C l; 2290 foreach(i; 0..50) 2291 { 2292 l.pushBack(new C(i)); 2293 } 2294 auto r = l.constRange; 2295 assert(equal(r.map!(c => c.c), iota(50))); 2296 } 2297 @("structs") 2298 @safe 2299 unittest 2300 { 2301 import std.format: format; 2302 import std.range; 2303 struct S 2304 { 2305 int s; 2306 string ss; 2307 this(int i) 2308 { 2309 s = i; 2310 ss = "%s".format(i); 2311 } 2312 } 2313 UnrolledList!(S) l; 2314 foreach(i; 0..50) 2315 { 2316 S s = S(i); 2317 l.pushBack(s); 2318 } 2319 auto r = l.constRange; 2320 assert(equal(r.map!(s => s.s), iota(50))); 2321 }