1 module util.multi_index; 2 3 /** 4 * TODO: 5 * random access index 6 * insertAfter ? insertBefore ? 7 * fix BitHackery 8 * make MutableView a per index thing? 9 * modify(r, mod, rollback) 10 * contain const/immutable value types 11 * other indices? 12 * dup 13 * make reserve perform reserve on all appropriate indices? 14 * ensure MultiIndexContainer is strongly exception safe. 15 */ 16 17 version = BucketHackery; 18 19 import std.array; 20 import std.range; 21 import std.exception: enforce; 22 import std.algorithm: find, swap, copy, fill, max, startsWith, moveAll; 23 import std.algorithm: move, sort, map; 24 import std.traits: isImplicitlyConvertible, isDynamicArray; 25 import util.replace: Replace; 26 import std.typetuple: TypeTuple, staticMap, NoDuplicates, staticIndexOf, allSatisfy; 27 import std.functional: unaryFun, binaryFun; 28 import std..string: format; 29 version(PtrHackery){ 30 import core.bitop: bt, bts, btr; 31 } 32 33 // stopgap allocator implementation 34 // drat: using GCAllocator is probably less efficient than arr.length = i 35 // cf GC.extend 36 37 struct GCAllocator{ 38 static T* allocate(T)(size_t i) { 39 return (new T[](i)).ptr; 40 } 41 42 static void deallocate(T)(T* t) { 43 // gc deallocates when it does. whee. 44 } 45 46 } 47 48 import core.stdc.stdlib: malloc, free; 49 import core.stdc..string: memset; 50 import core.memory: GC; 51 import core.exception: OutOfMemoryError; 52 53 struct MallocAllocator{ 54 static T* allocate(T)(size_t i) { 55 T* p = cast(T*) malloc(T.sizeof * i); 56 memset(p, 0, T.sizeof * i); 57 if(!p) throw new OutOfMemoryError(); 58 GC.addRange(cast(void*) p, T.sizeof * i); 59 return p; 60 } 61 static void deallocate(T)(T* t) { 62 GC.removeRange(cast(void*) t); 63 free(t); 64 } 65 } 66 67 import std.traits: isIterable, isNarrowString, ForeachType, Unqual; 68 // stolen from phobos and modified. 69 // when phobos gets real allocators, this hopefully will go away. 70 Unqual!(ForeachType!Range)[] allocatedArray(Allocator,Range)(Range r) 71 if (isIterable!Range && !isNarrowString!Range) 72 { 73 alias Unqual!(ForeachType!Range) E; 74 static if (hasLength!Range) 75 { 76 if(r.length == 0) return null; 77 78 auto result = Allocator.allocate!E(r.length)[0 .. r.length]; 79 80 size_t i = 0; 81 foreach (e; r) 82 { 83 // hacky 84 static if (is(typeof(e.opAssign(e)))) 85 { 86 // this should be in-place construction 87 emplace!E(result.ptr + i, e); 88 } 89 else 90 { 91 result[i] = e; 92 } 93 i++; 94 } 95 return result; 96 } 97 else 98 { 99 auto result = Allocator.allocate!(Unqual!E)(1)[0 .. 1]; 100 size_t i = 0; 101 foreach (e; r) 102 { 103 result[i] = e; 104 i++; 105 if(i == result.length) { 106 auto nlen = result.length*2+1; 107 auto nresult = Allocator.allocate!(Unqual!E)(nlen)[0 .. nlen]; 108 auto rest = moveAll(result, nresult); 109 fill(rest, E.init); 110 Allocator.deallocate(result.ptr); 111 result = nresult; 112 } 113 } 114 return result[0 .. i]; 115 } 116 } 117 118 template IsAllocator(T) { 119 enum bool IsAllocator = is(typeof(T.allocate!int(1)) == int*) && 120 is(typeof(T.deallocate!int((int*).init)) == void); 121 } 122 123 /// A doubly linked list index. 124 template Sequenced() { 125 // no memory allocations occur within this index. 126 enum bool BenefitsFromSignals = false; 127 // damn you, ddoc 128 /// _ 129 template Inner(ThisContainer,ThisNode, Value, ValueView, size_t N, Allocator) { 130 131 /** 132 Defines the index' primary range, which embodies a 133 bidirectional range 134 */ 135 struct SequencedRange(bool is_const) { 136 static if(is_const) { 137 alias const(ThisNode) Node; 138 alias const(ThisContainer) Container; 139 }else { 140 alias ThisContainer Container; 141 alias ThisNode Node; 142 } 143 Container c; 144 Node* _front, _back; 145 alias _front front_node; 146 alias _back back_node; 147 148 this(Container _c, Node* f, Node* b) { 149 c = _c; 150 _front = f; 151 _back = b; 152 } 153 154 @property bool empty() { 155 return 156 !(_front && _back && 157 _front !is _back.index!N.next && 158 _back !is _front.index!N.prev); 159 } 160 @property front(){ 161 return _front.value; 162 } 163 @property back(){ 164 return _back.value; 165 } 166 167 @property save(){ return this; } 168 169 void popFront() 170 in{ 171 assert(_front !is _front.index!N.next); 172 }body{ 173 _front = _front.index!N.next; 174 } 175 176 void popBack(){ 177 _back = _back.index!N.prev; 178 } 179 } 180 181 alias TypeTuple!(N,SequencedRange) IndexTuple; 182 alias TypeTuple!(N) NodeTuple; 183 184 // node implementation 185 mixin template NodeMixin(size_t N){ 186 typeof(this)* next, prev; 187 188 // inserts node between this and this.next 189 // a,b = this, this.next; then 190 // old: a <-> b, null <- node -> null 191 // new: a <-> node <-> b 192 void insertNext(typeof(this)* node) nothrow 193 in{ 194 assert(node !is null); 195 assert(node.index!N.prev is null, 196 format("node.prev = %x",node.index!N.prev)); 197 assert(node.index!N.next is null, 198 format("node.next = %x",node.index!N.next)); 199 }body{ 200 typeof(this)* n = next; 201 next = node; 202 node.index!N.prev = &this; 203 if(n !is null) n.index!N.prev = node; 204 node.index!N.next = n; 205 } 206 207 // a,b = this, this.prev; then 208 // old: b <-> a, null <- node -> null 209 // new: b <-> node <-> a 210 void insertPrev(typeof(this)* node) nothrow 211 in{ 212 assert(node !is null); 213 assert(node.index!N.prev is null, 214 format("node.prev = %x",node.index!N.prev)); 215 assert(node.index!N.next is null, 216 format("node.next = %x",node.index!N.next)); 217 }body{ 218 typeof(this)* p = prev; 219 if(p !is null) p.index!N.next = node; 220 node.index!N.prev = p; 221 prev = node; 222 node.index!N.next = &this; 223 } 224 225 // a,b,c = this, this.next, this.next.next; then 226 // old: a <-> b <-> c 227 // new: a <-> c, null <- b -> null 228 typeof(this)* removeNext() nothrow 229 in{ 230 assert(next); 231 }body{ 232 typeof(this)* n = next, nn = n.index!N.next; 233 next = nn; 234 if(nn) nn.index!N.prev = &this; 235 n.index!N.prev = n.index!N.next = null; 236 return n; 237 } 238 239 // a,b,c = this, this.prev, this.prev.prev; then 240 // old: c <-> b <-> a 241 // new: c <-> a, null <- b -> null 242 typeof(this)* removePrev() nothrow 243 in{ 244 assert(prev); 245 }body{ 246 typeof(this)* p = prev, pp = p.index!N.prev; 247 prev = pp; 248 if(pp) pp.index!N.next = &this; 249 p.index!N.prev = p.index!N.next = null; 250 return p; 251 } 252 } 253 254 /// Sequenced index implementation 255 /// 256 /// Requirements: the following symbols must be 257 /// defined in the scope in which this index is mixed in: 258 /// 259 // dangit, ddoc, show my single starting underscore! 260 /// ThisNode, Value, __InsertAllBut!N, __InsertAll, __Replace, 261 /// __RemoveAllBut!N, node_count 262 mixin template IndexMixin(size_t N, alias Range_0){ 263 ThisNode* _front, _back; 264 alias Range_0!false SeqRange; 265 alias Range_0!true ConstSeqRange; 266 267 template IsMyRange(T) { 268 enum bool IsMyRange = 269 is(T == SeqRange) || 270 is(T == ConstSeqRange); 271 } 272 273 /** 274 Returns the number of elements in the container. 275 276 Complexity: $(BIGOH 1). 277 */ 278 @property size_t length() const{ 279 return node_count; 280 } 281 282 /** 283 Property returning $(D true) if and only if the container has no 284 elements. 285 286 Complexity: $(BIGOH 1) 287 */ 288 @property bool empty() const{ 289 return node_count == 0; 290 } 291 292 /** 293 Fetch a range that spans all the elements in the container. 294 295 Complexity: $(BIGOH 1) 296 */ 297 SeqRange opSlice(){ 298 return SeqRange(this, _front, _back); 299 } 300 301 ConstSeqRange opSlice() const{ 302 return ConstSeqRange(this, _front, _back); 303 } 304 305 /** 306 Complexity: $(BIGOH 1) 307 */ 308 @property front() inout{ 309 return _front.value; 310 } 311 312 /** 313 Complexity: $(BIGOH r(n)); $(BR) $(BIGOH 1) for this index 314 */ 315 @property void front(Value value){ 316 _Replace(_front, value); 317 } 318 319 320 /** 321 * Complexity: $(BIGOH 1) 322 */ 323 @property back() inout{ 324 return _back.value; 325 } 326 327 /** 328 * Complexity: $(BIGOH r(n)) 329 */ 330 @property void back(Value value) { 331 _Replace(_back, value); 332 } 333 334 void _ClearIndex() { 335 _front = _back = null; 336 } 337 338 void clear(){ 339 _Clear(); 340 } 341 /** 342 Moves moveme.front to the position before tohere.front and inc both ranges. 343 Probably not safe to use either range afterwards, but who knows. 344 Preconditions: moveme and tohere are both ranges of the same container. 345 Postconditions: moveme.front is incremented 346 Complexity: $(BIGOH 1) 347 */ 348 void relocateFront(PosRange)(ref PosRange moveme, PosRange tohere) 349 if(is(ElementType!PosRange == Position!(ThisNode)) || 350 is(PosRange == SeqRange)) 351 in{ 352 // rubbish, now we can't ensure two ranges are from same 353 // index, container 354 static if(is(PosRange == SeqRange)) { 355 // well, do it if you can 356 assert(moveme.c == tohere.c); 357 assert(moveme.front_node); 358 assert(tohere.front_node); 359 }else { 360 assert(moveme.front.node); 361 assert(tohere.front.node); 362 } 363 }body{ 364 static if(is(PosRange == SeqRange)) { 365 ThisNode* m = moveme.front_node; 366 ThisNode* n = tohere.front_node; 367 }else { 368 ThisNode* m = moveme.front.node; 369 ThisNode* n = tohere.front.node; 370 } 371 moveme.popFront(); 372 if (m is n) return; //?? 373 if (m is n.index!N.prev) return; //?? 374 _Remove(m); 375 n.index!N.insertPrev(m); 376 if(n is _front) _front = m; 377 } 378 /** 379 Moves moveme.back to the position after tohere.back and dec both ranges. 380 Probably not safe to use either range afterwards, but who knows. 381 Preconditions: moveme and tohere are both ranges of the same container 382 Postconditions: moveme.back is decremented 383 Complexity: $(BIGOH 1) 384 */ 385 void relocateBack(PosRange)(ref PosRange moveme, PosRange tohere) 386 if(is(ElementType!PosRange == Position!(ThisNode)) || 387 is(PosRange == SeqRange)) 388 in{ 389 static if(is(PosRange == SeqRange)) { 390 assert(moveme.c == tohere.c); 391 assert(moveme.back_node); 392 assert(tohere.back_node); 393 }else { 394 assert(moveme.back.node); 395 assert(tohere.back.node); 396 } 397 }body{ 398 static if(is(PosRange == SeqRange)) { 399 ThisNode* m = moveme.back_node; 400 ThisNode* n = tohere.back_node; 401 }else{ 402 ThisNode* m = moveme.back.node; 403 ThisNode* n = tohere.back.node; 404 } 405 moveme.popBack(); 406 if (m is n) return; //?? 407 if (m is n.index!N.next) return; //?? 408 _Remove(m); 409 n.index!N.insertNext(m); 410 if(n is _back) _back = m; 411 } 412 413 void modify(SomeRange, Modifier)(SomeRange r, Modifier mod) 414 if(is(SomeRange == SeqRange) || 415 is(ElementType!SomeRange == Position!(ThisNode))) { 416 while(!r.empty) { 417 static if(is(SomeRange == SeqRange)){ 418 ThisNode* node = r.front_node; 419 }else{ 420 ThisNode* node = r.front.node; 421 } 422 _Modify(node, mod); 423 r.popFront(); 424 } 425 } 426 427 /** 428 Replaces r.front with value 429 Returns: whether replacement succeeded 430 Complexity: ?? 431 */ 432 bool replace(Position!ThisNode r, Value value) 433 { 434 return _Replace(r.node, value); 435 } 436 437 bool _insertFront(ThisNode* node) nothrow 438 in{ 439 assert(node !is null); 440 assert(node.index!N.prev is null); 441 assert(node.index!N.next is null); 442 }body{ 443 if(_front is null){ 444 debug assert(_back is null); 445 _front = _back = node; 446 }else{ 447 _front.index!N.insertPrev(node); 448 _front = node; 449 } 450 451 return true; 452 } 453 454 alias _insertBack _Insert; 455 456 bool _insertBack(ThisNode* node) nothrow 457 in{ 458 debug assert (node !is null); 459 }body{ 460 if(_front is null){ 461 debug assert(_back is null); 462 _front = _back = node; 463 }else{ 464 _back.index!N.insertNext(node); 465 _back = node; 466 } 467 468 return true; 469 } 470 471 /++ 472 Inserts every element of stuff not rejected by another index into the front 473 of the index. 474 Returns: 475 The number of elements inserted. 476 Complexity: $(BIGOH n $(SUB stuff) * i(n)); $(BR) $(BIGOH n $(SUB stuff)) for 477 this index 478 +/ 479 size_t insertFront(SomeRange)(SomeRange stuff) 480 if(isInputRange!SomeRange && 481 isImplicitlyConvertible!(ElementType!SomeRange, 482 ValueView)) 483 { 484 import std.array: empty, front; 485 if(stuff.empty) return 0; 486 size_t count = 0; 487 ThisNode* prev; 488 while(count == 0 && !stuff.empty){ 489 prev = _InsertAllBut!N(stuff.front); 490 if (!prev) continue; 491 _insertFront(prev); 492 stuff.popFront(); 493 count++; 494 } 495 foreach(item; stuff){ 496 ThisNode* node = _InsertAllBut!N(item); 497 if (!node) continue; 498 prev.index!N.insertNext(node); 499 prev = node; 500 count ++; 501 } 502 return count; 503 } 504 505 /++ 506 Inserts value into the front of the sequence, if no other index rejects value 507 Returns: 508 The number if elements inserted into the index. 509 Complexity: $(BIGOH i(n)); $(BR) $(BIGOH 1) for this index 510 +/ 511 size_t insertFront(SomeValue)(SomeValue value) 512 if(isImplicitlyConvertible!(SomeValue, ValueView)){ 513 ThisNode* node = _InsertAllBut!N(value); 514 if(!node) return 0; 515 _insertFront(node); 516 return 1; 517 } 518 519 /++ 520 Inserts every element of stuff not rejected by another index into the back 521 of the index. 522 Returns: 523 The number of elements inserted. 524 Complexity: $(BIGOH n $(SUB stuff) * i(n)); $(BR) $(BIGOH n $(SUB stuff)) for 525 this index 526 +/ 527 size_t insertBack (SomeRange)(SomeRange stuff) 528 if(isInputRange!SomeRange && 529 isImplicitlyConvertible!(ElementType!SomeRange, ValueView)) 530 { 531 size_t count = 0; 532 533 foreach(item; stuff){ 534 count += insertBack(item); 535 } 536 return count; 537 } 538 539 /++ 540 Inserts value into the back of the sequence, if no other index rejects value 541 Returns: 542 The number if elements inserted into the index. 543 Complexity: $(BIGOH i(n)); $(BR) $(BIGOH 1) for this index 544 +/ 545 size_t insertBack(SomeValue)(SomeValue value) 546 if(isImplicitlyConvertible!(SomeValue, ValueView)){ 547 ThisNode* node = _InsertAllBut!N(value); 548 if (!node) return 0; 549 _insertBack(node); 550 return 1; 551 } 552 553 /++ 554 Forwards to insertBack 555 +/ 556 alias insertBack insert; 557 558 // reckon we'll trust n is somewhere between _front and _back 559 void _Remove(ThisNode* n){ 560 if(n is _front){ 561 _removeFront(); 562 }else{ 563 ThisNode* prev = n.index!N.prev; 564 prev.index!N.removeNext(); 565 if(n is _back) _back = prev; 566 } 567 } 568 569 ThisNode* _removeFront() 570 in{ 571 assert(_back !is null); 572 assert(_front !is null); 573 }body{ 574 ThisNode* n = _front; 575 if(_back == _front){ 576 _back = _front = null; 577 }else{ 578 _front = _front.index!N.next; 579 n.index!N.next = null; 580 _front.index!N.prev = null; 581 } 582 return n; 583 } 584 585 /++ 586 Removes the value at the front of the index from the container. 587 Precondition: $(D !empty) 588 Complexity: $(BIGOH d(n)); $(BIGOH 1) for this index 589 +/ 590 void removeFront(){ 591 _RemoveAll(_front); 592 } 593 594 /++ 595 Removes the value at the back of the index from the container. 596 Precondition: $(D !empty) 597 Complexity: $(BIGOH d(n)); $(BR) $(BIGOH 1) for this index 598 +/ 599 void removeBack(){ 600 _RemoveAll(_back); 601 } 602 /++ 603 Forwards to removeBack 604 +/ 605 alias removeBack removeAny; 606 607 /++ 608 Removes the values of r from the container. 609 Preconditions: r came from this index 610 Complexity: $(BIGOH n $(SUB r) * d(n)), $(BR) $(BIGOH n $(SUB r)) for this index 611 +/ 612 SeqRange remove(R)(R r) 613 if(is(R == SeqRange) || 614 is(ElementType!R == Position!ThisNode)) 615 { 616 while(!r.empty){ 617 static if(is(R == SeqRange)){ 618 ThisNode* f = r.front_node; 619 }else{ 620 ThisNode* f = r.front.node; 621 r.front.obliterated = true; 622 } 623 r.popFront(); 624 _RemoveAll(f); 625 } 626 return SeqRange(this,null,null); 627 } 628 // in: old is from this index 629 // out: old is disconnected from this index and replaced by newnode 630 void _NodeReplace(ThisNode* old, ThisNode* newnode) { 631 ThisNode* next = old.index!N.next; 632 ThisNode* prev = old.index!N.prev; 633 newnode.index!N.next = next; 634 newnode.index!N.prev = prev; 635 if(next) { 636 next.index!N.prev = newnode; 637 }else { 638 assert(old is _back); 639 _back = newnode; 640 } 641 if(prev) { 642 prev.index!N.next = newnode; 643 }else{ 644 assert(old is _front); 645 _front = newnode; 646 } 647 648 old.index!N.prev = null; 649 old.index!N.next = null; 650 } 651 652 653 void _Check(){ 654 } 655 656 string toString0(){ 657 string r = "["; 658 auto rng = opSlice(); 659 while(!rng.empty){ 660 r ~= format("%s", rng.front); 661 rng.popFront(); 662 r ~= rng.empty ? "]" : ", "; 663 } 664 return r; 665 } 666 667 private SeqRange fromNode(ThisNode* n){ 668 return SeqRange(this, n, this.index!N._back); 669 } 670 } 671 672 } 673 } 674 675 /// A random access index. 676 template RandomAccess() { 677 enum bool BenefitsFromSignals = false; 678 /// _ 679 template Inner(ThisContainer,ThisNode, Value, ValueView, size_t N, Allocator) { 680 alias TypeTuple!() NodeTuple; 681 alias TypeTuple!(N,ThisContainer) IndexTuple; 682 683 // node implementation 684 mixin template NodeMixin(){ 685 size_t _index; 686 } 687 688 /// index implementation 689 /// 690 /// Requirements: the following symbols must be 691 /// defined in the scope in which this index is mixed in: 692 /// 693 // dangit, ddoc, show my single starting underscore! 694 /// ThisNode, Value, __InsertAllBut!N, __InsertAll, __Replace, 695 /// __RemoveAllBut!N, node_count 696 mixin template IndexMixin(size_t N, ThisContainer){ 697 ThisNode*[] ra; 698 699 /// Defines the index' primary range, which embodies a 700 /// random access range 701 struct RARangeT(bool is_const) { 702 static if(is_const) { 703 alias const(ThisNode) Node; 704 alias const(ThisContainer) Container; 705 }else { 706 alias ThisContainer Container; 707 alias ThisNode Node; 708 } 709 Container c; 710 size_t s, e; 711 712 this(Container _c, size_t _s, size_t _e) { 713 c = _c; 714 s = _s; 715 e = _e; 716 } 717 718 private @property Node* front_node(){ 719 assert(s < e && e <= c.index!N.length); 720 return c.index!N.ra[s]; 721 } 722 private @property Node* back_node() { 723 assert(s < e && e <= c.index!N.length); 724 return c.index!N.ra[e-1]; 725 } 726 727 @property front(){ 728 assert(s < e && e <= c.index!N.length); 729 return front_node.value; 730 } 731 732 void popFront(){ s++; } 733 734 @property bool empty()const{ return s >= e; } 735 @property size_t length()const { return s <= e ? e-s : 0; } 736 737 @property back(){ 738 return back_node.value; 739 } 740 741 void popBack(){ e--; } 742 743 @property save(){ return this; } 744 745 auto opIndex(size_t i){ return nth_node(i).value; } 746 747 private auto nth_node(size_t i) { return c.index!N.ra[i]; } 748 749 auto opSlice(size_t a, size_t b) { 750 assert(a <= b && b < length); 751 return RARangeT(c, s+a, s+b); 752 } 753 754 static if(!is_const) { 755 private @property front_node(ThisNode* n) { 756 assert(s < e && e <= c.index!N.length); 757 c.index!N.ra[s] = n; 758 } 759 } 760 } 761 762 763 alias RARangeT!true ConstRARange; 764 alias RARangeT!false RARange; 765 766 /* 767 static assert(is(typeof( 768 { 769 RARange r = void; // can define a range object 770 if (r.empty) {} // can test for empty 771 r.popFront(); // can invoke popFront() 772 auto h = r.front; // can get the front of the range 773 }))); 774 775 static assert(isInputRange!RARange); 776 static assert(isForwardRange!RARange); 777 static assert(isBidirectionalRange!RARange); 778 static assert(isRandomAccessRange!RARange); 779 */ 780 781 template IsMyRange(T) { 782 enum bool IsMyRange = 783 is(T == RARange) || 784 is(T == ConstRARange); 785 } 786 787 788 /** 789 Fetch a range that spans all the elements in the container. 790 791 Complexity: $(BIGOH 1) 792 */ 793 RARange opSlice (){ 794 return RARange(this, 0, node_count); 795 } 796 ConstRARange opSlice () const{ 797 return ConstRARange(this, 0, node_count); 798 } 799 800 /** 801 Fetch a range that spans all the elements in the container from 802 index $(D a) (inclusive) to index $(D b) (exclusive). 803 Preconditions: a <= b && b <= length 804 805 Complexity: $(BIGOH 1) 806 */ 807 RARange opSlice(size_t a, size_t b){ 808 enforce(a <= b && b <= length); 809 return RARange(this, a, b); 810 } 811 ConstRARange opSlice(size_t a, size_t b) const{ 812 enforce(a <= b && b <= length); 813 return ConstRARange(this, a, b); 814 } 815 816 /** 817 Returns the number of elements in the container. 818 819 Complexity: $(BIGOH 1). 820 */ 821 @property size_t length()const{ 822 return node_count; 823 } 824 825 /** 826 Property returning $(D true) if and only if the container has no elements. 827 828 Complexity: $(BIGOH 1) 829 */ 830 @property bool empty() const{ 831 return node_count == 0; 832 } 833 834 /** 835 Returns the _capacity of the index, which is the length of the 836 underlying store 837 */ 838 @property size_t capacity() const{ 839 return ra.length; 840 } 841 842 /** 843 Ensures sufficient capacity to accommodate $(D count) elements. 844 845 Postcondition: $(D capacity >= count) 846 847 Complexity: $(BIGOH ??) if $(D e > capacity), 848 otherwise $(BIGOH 1). 849 */ 850 void reserve(size_t count){ 851 if(ra.length < count){ 852 auto newra = Allocator.allocate!(ThisNode*)(count)[0 .. count]; 853 auto rest = moveAll(ra, newra); 854 fill(rest, null); 855 Allocator.deallocate(ra.ptr); 856 ra = newra; 857 } 858 } 859 860 /** 861 Complexity: $(BIGOH 1) 862 */ 863 @property front() inout{ 864 return ra[0].value; 865 } 866 867 /** 868 Complexity: $(BIGOH r(n)); $(BR) $(BIGOH 1) for this index 869 */ 870 @property void front(ValueView value){ 871 _Replace(ra[0], cast(Value) value); 872 } 873 874 /** 875 Complexity: $(BIGOH 1) 876 */ 877 @property back() inout{ 878 return ra[node_count-1].value; 879 } 880 881 /** 882 Complexity: $(BIGOH r(n)); $(BR) $(BIGOH 1) for this index 883 */ 884 @property void back(ValueView value){ 885 _Replace(ra[node_count-1], cast(Value) value); 886 } 887 888 void _ClearIndex(){ 889 fill(ra, (ThisNode*).init); 890 } 891 892 /// _ 893 void clear(){ 894 _Clear(); 895 } 896 897 /** 898 Preconditions: i < length 899 Complexity: $(BIGOH 1) 900 */ 901 auto opIndex(size_t i) inout{ 902 enforce(i < length); 903 return ra[i].value; 904 } 905 /** 906 Sets index i to value, unless another index refuses value 907 Preconditions: i < length 908 Returns: the resulting _value at index i 909 Complexity: $(BIGOH r(n)); $(BR) $(BIGOH 1) for this index 910 */ 911 ValueView opIndexAssign(ValueView value, size_t i){ 912 enforce(i < length); 913 _Replace(ra[i], cast(Value) value); 914 return ra[i].value; 915 } 916 917 /** 918 Swaps element at index $(D i) with element at index $(D j). 919 Preconditions: i < length && j < length 920 Complexity: $(BIGOH 1) 921 */ 922 void swapAt( size_t i, size_t j){ 923 enforce(i < length && j < length); 924 swap(ra[i], ra[j]); 925 swap(ra[i].index!N._index, ra[j].index!N._index); 926 } 927 928 /** 929 Removes the last element from this index. 930 Preconditions: !empty 931 Complexity: $(BIGOH d(n)); $(BR) $(BIGOH 1) for this index 932 */ 933 void removeBack(){ 934 _RemoveAllBut!N(ra[node_count-1]); 935 dealloc(ra[node_count]); 936 ra[node_count] = null; 937 } 938 939 alias removeBack removeAny; 940 941 void _Remove(ThisNode* n){ 942 size_t i = n.index!N._index; 943 copy(ra[i+1 .. node_count], ra[i .. node_count-1]); 944 foreach(k,r; ra[i .. node_count-1]) 945 r.index!N._index = i+k; 946 ra[node_count-1] = null; 947 return; 948 } 949 950 /** 951 inserts value in the back of this index. 952 Complexity: $(BIGOH i(n)), $(BR) amortized $(BIGOH 1) for this index 953 */ 954 size_t insertBack(SomeValue)(SomeValue value) 955 if(isImplicitlyConvertible!(SomeValue, ValueView)) 956 { 957 ThisNode* n = _InsertAllBut!N(value); 958 if (!n) return 0; 959 node_count--; 960 _Insert(n); 961 node_count++; 962 return 1; 963 } 964 965 /** 966 inserts elements of r in the back of this index. 967 Complexity: $(BIGOH n $(SUB r) * i(n)), $(BR) amortized $(BIGOH n $(SUB r)) 968 for this index 969 */ 970 size_t insertBack(SomeRange)(SomeRange r) 971 if(isImplicitlyConvertible!(ElementType!SomeRange, ValueView)) 972 { 973 enum haslen = hasLength!SomeRange; 974 975 static if(haslen){ 976 if(capacity() < node_count + r.length){ 977 reserve(node_count + r.length); 978 } 979 } 980 size_t count = 0; 981 foreach(e; r){ 982 count += insertBack(e); 983 } 984 return count; 985 } 986 987 void _Insert(ThisNode* node){ 988 if (node_count >= ra.length){ 989 reserve(max(ra.length * 2 + 1, node_count+1)); 990 } 991 ra[node_count] = node; 992 ra[node_count].index!N._index = node_count; 993 } 994 995 /** 996 inserts elements of r in the back of this index. 997 Complexity: $(BIGOH n $(SUB r) * i(n)), $(BR) amortized $(BIGOH n $(SUB r)) 998 for this index 999 */ 1000 alias insertBack insert; 1001 1002 /** 1003 Perform mod on r.front and performs any necessary fixups to container's 1004 indices. If the result of mod violates any index' invariant, r.front is 1005 removed from the container. 1006 Preconditions: !r.empty, $(BR) 1007 mod is a callable of the form void mod(ref Value) 1008 Complexity: $(BIGOH m(n)), $(BR) $(BIGOH 1) for this index 1009 */ 1010 1011 void modify(SomeRange, Modifier)(SomeRange r, Modifier mod) 1012 if(is(SomeRange == RARange) || 1013 is(ElementType!SomeRange == Position!(ThisNode))) { 1014 while(!r.empty) { 1015 static if(is(SomeRange == RARange)){ 1016 ThisNode* node = r.front_node; 1017 }else{ 1018 ThisNode* node = r.front.node; 1019 } 1020 _Modify(node, mod); 1021 r.popFront(); 1022 } 1023 } 1024 /** 1025 Replaces r.front with value 1026 Returns: whether replacement succeeded 1027 Complexity: ?? 1028 */ 1029 bool replace(Position!ThisNode r, ValueView value) { 1030 return _Replace(r.node, cast(Value) value); 1031 } 1032 1033 static bool _RemovePred(Position!ThisNode a, Position!ThisNode b) { 1034 return a.node.index!N._index < b.node.index!N._index; 1035 } 1036 static size_t _RemoveUn(Position!ThisNode a) { 1037 return a.node.index!N._index; 1038 } 1039 static size_t _RemoveUn2(ThisNode* a) { 1040 return a.index!N._index; 1041 } 1042 /** 1043 removes elements of r from this container. 1044 Complexity: $(BIGOH n $(SUB r) * d(n)), $(BR) $(BIGOH n) 1045 for this index 1046 */ 1047 RARange remove(Range)(Range r) 1048 if(is(Range == RARange) || 1049 is(ElementType!Range == Position!ThisNode)) { 1050 static if(is(Range == RARange)) { 1051 // definitely contiguous 1052 size_t _length = node_count; 1053 size_t s = r.front_node.index!N._index; 1054 size_t e = r.back_node.index!N._index+1; 1055 size_t newlen = _length - (e-s); 1056 while(!r.empty){ 1057 ThisNode* node = r.front_node; 1058 _RemoveAllBut!N(node); 1059 dealloc(node); 1060 r.popFront(); 1061 } 1062 copy(ra[e .. _length], ra[s .. newlen]); 1063 foreach(k, rx; ra[s .. newlen]) { 1064 rx.index!N._index = s+k; 1065 } 1066 fill(ra[newlen .. _length], cast(ThisNode*) null); 1067 _length -= e-s; 1068 }else { 1069 // maybe not contiguous 1070 // need to be efficient with moving chunks 1071 auto arr = allocatedArray!Allocator(r); 1072 sort!_RemovePred(arr); 1073 if(arr.length == 1) _RemoveAll(arr[0].node); 1074 else{ 1075 auto ixs = map!_RemoveUn(arr); 1076 auto ab = zip(ixs, chain(drop(ixs, 1), [node_count])); 1077 size_t p = ixs.front; 1078 foreach(a,b; ab) { 1079 auto pstart = p; 1080 p += b-a-1; 1081 _RemoveAllBut!N(ra[a]); 1082 dealloc(ra[a]); 1083 copy(ra[a+1 .. b], ra[pstart .. p]); 1084 foreach(k, n; arr[pstart .. p]) 1085 n.node.index!N._index = pstart+k; 1086 } 1087 fill(ra[p .. $], cast(ThisNode*) null); 1088 } 1089 foreach(p; arr) p.obliterated = true; 1090 } 1091 return RARange(this, 0, 0); 1092 } 1093 1094 void _NodeReplace(ThisNode* old, ThisNode* newnode) { 1095 move(newnode, ra[old.index!N._index]); 1096 newnode.index!N._index = old.index!N._index; 1097 } 1098 1099 void _Check(){ 1100 foreach(i, n; ra[0 .. node_count]) { 1101 assert(n.index!N._index == i); 1102 } 1103 } 1104 1105 string toString0(){ 1106 string r = "["; 1107 auto rng = opSlice(); 1108 while(!rng.empty){ 1109 r ~= format("%s", rng.front); 1110 rng.popFront(); 1111 r ~= rng.empty ? "]" : ", "; 1112 } 1113 return r; 1114 } 1115 1116 private RARange fromNode(ThisNode* n){ 1117 size_t ix = n.index!N._index; 1118 return RARange(this, ix, this.node_count); 1119 } 1120 } 1121 } 1122 } 1123 1124 // RBTree node impl. taken from std.container - that's Steven Schveighoffer's 1125 // code - and modified to suit. 1126 1127 /** 1128 * Enumeration determining what color the node is. Null nodes are assumed 1129 * to be black. 1130 */ 1131 enum Color : byte 1132 { 1133 Red, 1134 Black 1135 } 1136 1137 /// ordered node implementation 1138 mixin template OrderedNodeMixin(size_t N){ 1139 alias typeof(this)* Node; 1140 Node _left; 1141 Node _right; 1142 1143 version(PtrHackery){ 1144 size_t _p; 1145 1146 @property void _parent(Node p){ 1147 Color c = color; 1148 _p = cast(size_t) p; 1149 color = c; 1150 } 1151 @property Node _parent(){ 1152 size_t r = _p; 1153 btr(&r,0); 1154 return cast(Node) r; 1155 } 1156 1157 @property void color(Color c){ 1158 if(c) bts(&_p,0); 1159 else btr(&_p,0); 1160 } 1161 @property Color color(){ 1162 return cast(Color) bt(&_p,0); 1163 } 1164 }else{ 1165 Node _parent; 1166 /** 1167 * The color of the node. 1168 */ 1169 Color color; 1170 } 1171 1172 /** 1173 * Get the left child 1174 */ 1175 @property inout(typeof(this))* left() inout 1176 { 1177 return _left; 1178 } 1179 1180 /** 1181 * Get the right child 1182 */ 1183 @property inout(typeof(this))* right() inout 1184 { 1185 return _right; 1186 } 1187 1188 /** 1189 * Get the parent 1190 */ 1191 @property Node parent() 1192 { 1193 return _parent; 1194 } 1195 1196 /** 1197 * Set the left child. Also updates the new child's parent node. This 1198 * does not update the previous child. 1199 * 1200 * Returns newNode 1201 */ 1202 @property Node left(Node newNode) 1203 { 1204 _left = newNode; 1205 if(newNode !is null) 1206 newNode.index!N._parent = &this; 1207 return newNode; 1208 } 1209 1210 /** 1211 * Set the right child. Also updates the new child's parent node. This 1212 * does not update the previous child. 1213 * 1214 * Returns newNode 1215 */ 1216 @property Node right(Node newNode) 1217 { 1218 _right = newNode; 1219 if(newNode !is null) 1220 newNode.index!N._parent = &this; 1221 return newNode; 1222 } 1223 1224 // assume _left is not null 1225 // 1226 // performs rotate-right operation, where this is T, _right is R, _left is 1227 // L, _parent is P: 1228 // 1229 // P P 1230 // | -> | 1231 // T L 1232 // / \ / \ 1233 // L R a T 1234 // / \ / \ 1235 // a b b R 1236 // 1237 /** 1238 * Rotate right. This performs the following operations: 1239 * - The left child becomes the parent of this node. 1240 * - This node becomes the new parent's right child. 1241 * - The old right child of the new parent becomes the left child of this 1242 * node. 1243 */ 1244 Node rotateR() 1245 in 1246 { 1247 assert(_left !is null); 1248 } 1249 body 1250 { 1251 // sets _left._parent also 1252 if(isLeftNode) 1253 parent.index!N.left = _left; 1254 else 1255 parent.index!N.right = _left; 1256 Node tmp = _left.index!N._right; 1257 1258 // sets _parent also 1259 _left.index!N.right = &this; 1260 1261 // sets tmp._parent also 1262 left = tmp; 1263 1264 return &this; 1265 } 1266 1267 // assumes _right is non null 1268 // 1269 // performs rotate-left operation, where this is T, _right is R, _left is 1270 // L, _parent is P: 1271 // 1272 // P P 1273 // | -> | 1274 // T R 1275 // / \ / \ 1276 // L R T b 1277 // / \ / \ 1278 // a b L a 1279 // 1280 /** 1281 * Rotate left. This performs the following operations: 1282 * - The right child becomes the parent of this node. 1283 * - This node becomes the new parent's left child. 1284 * - The old left child of the new parent becomes the right child of this 1285 * node. 1286 */ 1287 Node rotateL() 1288 in 1289 { 1290 assert(_right !is null); 1291 } 1292 body 1293 { 1294 // sets _right._parent also 1295 if(isLeftNode) 1296 parent.index!N.left = _right; 1297 else 1298 parent.index!N.right = _right; 1299 Node tmp = _right.index!N._left; 1300 1301 // sets _parent also 1302 _right.index!N.left = &this; 1303 1304 // sets tmp._parent also 1305 right = tmp; 1306 return &this; 1307 } 1308 1309 1310 /** 1311 * Returns true if this node is a left child. 1312 * 1313 * Note that this should always return a value because the root has a 1314 * parent which is the marker node. 1315 */ 1316 @property bool isLeftNode() const 1317 in 1318 { 1319 assert(_parent !is null); 1320 } 1321 body 1322 { 1323 return _parent.index!N._left is &this; 1324 } 1325 1326 /** 1327 * Set the color of the node after it is inserted. This performs an 1328 * update to the whole tree, possibly rotating nodes to keep the Red-Black 1329 * properties correct. This is an O(lg(n)) operation, where n is the 1330 * number of nodes in the tree. 1331 * 1332 * end is the marker node, which is the parent of the topmost valid node. 1333 */ 1334 void setColor(Node end) 1335 { 1336 // test against the marker node 1337 if(_parent !is end) 1338 { 1339 if(_parent.index!N.color == Color.Red) 1340 { 1341 Node cur = &this; 1342 while(true) 1343 { 1344 // because root is always black, _parent._parent always exists 1345 if(cur.index!N._parent.index!N.isLeftNode) 1346 { 1347 // parent is left node, y is 'uncle', could be null 1348 Node y = cur.index!N._parent.index!N._parent.index!N._right; 1349 if(y !is null && y.index!N.color == Color.Red) 1350 { 1351 cur.index!N._parent.index!N.color = Color.Black; 1352 y.index!N.color = Color.Black; 1353 cur = cur.index!N._parent.index!N._parent; 1354 if(cur.index!N._parent is end) 1355 { 1356 // root node 1357 cur.index!N.color = Color.Black; 1358 break; 1359 } 1360 else 1361 { 1362 // not root node 1363 cur.index!N.color = Color.Red; 1364 if(cur.index!N._parent.index!N.color == Color.Black) 1365 // satisfied, exit the loop 1366 break; 1367 } 1368 } 1369 else 1370 { 1371 if(!cur.index!N.isLeftNode) 1372 cur = cur.index!N._parent.index!N.rotateL(); 1373 cur.index!N._parent.index!N.color = Color.Black; 1374 cur = cur.index!N._parent.index!N._parent.index!N.rotateR(); 1375 cur.index!N.color = Color.Red; 1376 // tree should be satisfied now 1377 break; 1378 } 1379 } 1380 else 1381 { 1382 // parent is right node, y is 'uncle' 1383 Node y = cur.index!N._parent.index!N._parent.index!N._left; 1384 if(y !is null && y.index!N.color == Color.Red) 1385 { 1386 cur.index!N._parent.index!N.color = Color.Black; 1387 y.index!N.color = Color.Black; 1388 cur = cur.index!N._parent.index!N._parent; 1389 if(cur.index!N._parent is end) 1390 { 1391 // root node 1392 cur.index!N.color = Color.Black; 1393 break; 1394 } 1395 else 1396 { 1397 // not root node 1398 cur.index!N.color = Color.Red; 1399 if(cur.index!N._parent.index!N.color == Color.Black) 1400 // satisfied, exit the loop 1401 break; 1402 } 1403 } 1404 else 1405 { 1406 if(cur.index!N.isLeftNode) 1407 cur = cur.index!N._parent.index!N.rotateR(); 1408 cur.index!N._parent.index!N.color = Color.Black; 1409 cur = cur.index!N._parent.index!N._parent.index!N.rotateL(); 1410 cur.index!N.color = Color.Red; 1411 // tree should be satisfied now 1412 break; 1413 } 1414 } 1415 } 1416 1417 } 1418 } 1419 else 1420 { 1421 // 1422 // this is the root node, color it black 1423 // 1424 color = Color.Black; 1425 } 1426 } 1427 1428 /** 1429 * Remove this node from the tree. The 'end' node is used as the marker 1430 * which is root's parent. Note that this cannot be null! 1431 * 1432 * Returns the next highest valued node in the tree after this one, or end 1433 * if this was the highest-valued node. 1434 */ 1435 Node remove(Node end) 1436 { 1437 // 1438 // remove this node from the tree, fixing the color if necessary. 1439 // 1440 Node x; 1441 Node ret; 1442 if(_left is null || _right is null) 1443 { 1444 ret = next; 1445 } 1446 else 1447 { 1448 // 1449 // normally, we can just swap this node's and y's value, but 1450 // because an iterator could be pointing to y and we don't want to 1451 // disturb it, we swap this node and y's structure instead. This 1452 // can also be a benefit if the value of the tree is a large 1453 // struct, which takes a long time to copy. 1454 // 1455 Node yp, yl, yr; 1456 Node y = next; 1457 yp = y.index!N._parent; 1458 yl = y.index!N._left; 1459 yr = y.index!N._right; 1460 auto yc = y.index!N.color; 1461 auto isyleft = y.index!N.isLeftNode; 1462 1463 // 1464 // replace y's structure with structure of this node. 1465 // 1466 if(isLeftNode) 1467 _parent.index!N.left = y; 1468 else 1469 _parent.index!N.right = y; 1470 // 1471 // need special case so y doesn't point back to itself 1472 // 1473 y.index!N.left = _left; 1474 if(_right is y) 1475 y.index!N.right = &this; 1476 else 1477 y.index!N.right = _right; 1478 y.index!N.color = color; 1479 1480 // 1481 // replace this node's structure with structure of y. 1482 // 1483 left = yl; 1484 right = yr; 1485 if(_parent !is y) 1486 { 1487 if(isyleft) 1488 yp.index!N.left = &this; 1489 else 1490 yp.index!N.right = &this; 1491 } 1492 color = yc; 1493 1494 // 1495 // set return value 1496 // 1497 ret = y; 1498 } 1499 1500 // if this has less than 2 children, remove it 1501 if(_left !is null) 1502 x = _left; 1503 else 1504 x = _right; 1505 1506 // remove this from the tree at the end of the procedure 1507 bool removeThis = false; 1508 if(x is null) 1509 { 1510 // pretend this is a null node, remove this on finishing 1511 x = &this; 1512 removeThis = true; 1513 } 1514 else if(isLeftNode) 1515 _parent.index!N.left = x; 1516 else 1517 _parent.index!N.right = x; 1518 1519 // if the color of this is black, then it needs to be fixed 1520 if(color == color.Black) 1521 { 1522 // need to recolor the tree. 1523 while(x.index!N._parent !is end && x.index!N.color == Color.Black) 1524 { 1525 if(x.index!N.isLeftNode) 1526 { 1527 // left node 1528 Node w = x.index!N._parent.index!N._right; 1529 if(w.index!N.color == Color.Red) 1530 { 1531 w.index!N.color = Color.Black; 1532 x.index!N._parent.index!N.color = Color.Red; 1533 x.index!N._parent.index!N.rotateL(); 1534 w = x.index!N._parent.index!N._right; 1535 } 1536 Node wl = w.index!N.left; 1537 Node wr = w.index!N.right; 1538 if((wl is null || wl.index!N.color == Color.Black) && 1539 (wr is null || wr.index!N.color == Color.Black)) 1540 { 1541 w.index!N.color = Color.Red; 1542 x = x.index!N._parent; 1543 } 1544 else 1545 { 1546 if(wr is null || wr.index!N.color == Color.Black) 1547 { 1548 // wl cannot be null here 1549 wl.index!N.color = Color.Black; 1550 w.index!N.color = Color.Red; 1551 w.index!N.rotateR(); 1552 w = x.index!N._parent.index!N._right; 1553 } 1554 1555 w.index!N.color = x.index!N._parent.index!N.color; 1556 x.index!N._parent.index!N.color = Color.Black; 1557 w.index!N._right.index!N.color = Color.Black; 1558 x.index!N._parent.index!N.rotateL(); 1559 x = end.index!N.left; // x = root 1560 } 1561 } 1562 else 1563 { 1564 // right node 1565 Node w = x.index!N._parent.index!N._left; 1566 if(w.index!N.color == Color.Red) 1567 { 1568 w.index!N.color = Color.Black; 1569 x.index!N._parent.index!N.color = Color.Red; 1570 x.index!N._parent.index!N.rotateR(); 1571 w = x.index!N._parent.index!N._left; 1572 } 1573 Node wl = w.index!N.left; 1574 Node wr = w.index!N.right; 1575 if((wl is null || wl.index!N.color == Color.Black) && 1576 (wr is null || wr.index!N.color == Color.Black)) 1577 { 1578 w.index!N.color = Color.Red; 1579 x = x.index!N._parent; 1580 } 1581 else 1582 { 1583 if(wl is null || wl.index!N.color == Color.Black) 1584 { 1585 // wr cannot be null here 1586 wr.index!N.color = Color.Black; 1587 w.index!N.color = Color.Red; 1588 w.index!N.rotateL(); 1589 w = x.index!N._parent.index!N._left; 1590 } 1591 1592 w.index!N.color = x.index!N._parent.index!N.color; 1593 x.index!N._parent.index!N.color = Color.Black; 1594 w.index!N._left.index!N.color = Color.Black; 1595 x.index!N._parent.index!N.rotateR(); 1596 x = end.index!N.left; // x = root 1597 } 1598 } 1599 } 1600 x.index!N.color = Color.Black; 1601 } 1602 1603 if(removeThis) 1604 { 1605 // 1606 // clear this node out of the tree 1607 // 1608 if(isLeftNode) 1609 _parent.index!N.left = null; 1610 else 1611 _parent.index!N.right = null; 1612 } 1613 1614 return ret; 1615 } 1616 1617 /** 1618 * Return the leftmost descendant of this node. 1619 */ 1620 @property leftmost() inout 1621 { 1622 typeof(this)* result = &this; 1623 while(result.index!N._left !is null) 1624 result = result.index!N._left; 1625 return result; 1626 } 1627 1628 /** 1629 * Return the rightmost descendant of this node 1630 */ 1631 @property rightmost() inout 1632 { 1633 auto result = &this; 1634 while(result.index!N._right !is null) 1635 result = result.index!N._right; 1636 return result; 1637 } 1638 1639 @property parentmost() inout 1640 { 1641 auto result = &this; 1642 while(result.index!N._parent !is null) 1643 result = result.index!N._parent; 1644 return result; 1645 } 1646 1647 /** 1648 * Returns the next valued node in the tree. 1649 * 1650 * You should never call this on the marker node, as it is assumed that 1651 * there is a valid next node. 1652 */ 1653 @property inout(typeof(this))* next() inout 1654 in{ 1655 debug assert( &this !is this.index!N.parentmost.index!N.rightmost, 1656 "calling prev on _end.rightmost"); 1657 }body{ 1658 auto n = &this; 1659 if(n.index!N.right is null) 1660 { 1661 while(!n.index!N.isLeftNode) 1662 n = n.index!N._parent; 1663 return n.index!N._parent; 1664 } 1665 else 1666 return n.index!N.right.index!N.leftmost; 1667 } 1668 1669 /** 1670 * Returns the previous valued node in the tree. 1671 * 1672 * You should never call this on the leftmost node of the tree as it is 1673 * assumed that there is a valid previous node. 1674 */ 1675 @property inout(typeof(this))* prev() inout 1676 in{ 1677 debug assert( &this !is this.index!N.parentmost.index!N.leftmost, 1678 "calling prev on _end.leftmost"); 1679 }body{ 1680 auto n = &this; 1681 if(n.index!N.left is null) 1682 { 1683 while(n.index!N.isLeftNode) 1684 n = n.index!N._parent; 1685 n = n.index!N._parent; 1686 return n; 1687 } 1688 else 1689 return n.index!N.left.index!N.rightmost; 1690 } 1691 1692 } 1693 1694 /// ordered index implementation 1695 mixin template OrderedIndex(size_t N, bool allowDuplicates, alias KeyFromValue, alias Compare, ThisContainer) { 1696 // this index does do memory allocation 1697 // 1) in removeKey, moves stuff to allocated array 1698 // 2) somewhere does new Exception(...) 1699 alias ThisNode* Node; 1700 alias binaryFun!Compare _less; 1701 alias unaryFun!KeyFromValue key; 1702 alias typeof(key(Value.init)) KeyType; 1703 1704 /** 1705 * The range type for this index, which embodies a bidirectional range 1706 */ 1707 struct OrderedRangeT(bool is_const) 1708 { 1709 static if(is_const) { 1710 alias const(ThisNode) Node; 1711 alias const(ThisContainer) Container; 1712 }else { 1713 alias ThisContainer Container; 1714 alias ThisNode Node; 1715 } 1716 Container c; 1717 private Node* _begin; 1718 private Node* _end; 1719 1720 this(Container _c, Node* b, Node* e) { 1721 c = _c; 1722 _begin = b; 1723 _end = e; 1724 } 1725 1726 /** 1727 * Returns $(D true) if the range is _empty 1728 */ 1729 @property bool empty() const 1730 { 1731 return _begin is _end; 1732 } 1733 1734 @property front_node() { 1735 return _begin; 1736 }; 1737 1738 @property back_node() { 1739 return _end.index!N.prev; 1740 } 1741 /** 1742 * Returns the first element in the range 1743 */ 1744 @property front() 1745 { 1746 return front_node.value; 1747 } 1748 1749 /** 1750 * Returns the last element in the range 1751 */ 1752 @property back() 1753 { 1754 return back_node.value; 1755 } 1756 1757 /** 1758 * pop the front element from the range 1759 * 1760 * complexity: amortized $(BIGOH 1) 1761 */ 1762 void popFront() 1763 { 1764 _begin = _begin.index!N.next; 1765 } 1766 1767 /** 1768 * pop the back element from the range 1769 * 1770 * complexity: amortized $(BIGOH 1) 1771 */ 1772 void popBack() 1773 { 1774 _end = _end.index!N.prev; 1775 } 1776 1777 /** 1778 * Trivial _save implementation, needed for $(D isForwardRange). 1779 */ 1780 @property save() 1781 { 1782 return this; 1783 } 1784 } 1785 1786 alias OrderedRangeT!true ConstOrderedRange; 1787 alias OrderedRangeT!false OrderedRange; 1788 1789 template IsMyRange(T) { 1790 enum bool IsMyRange = 1791 is(T == OrderedRange) || 1792 is(T == ConstOrderedRange); 1793 } 1794 1795 auto _add(Node n) 1796 { 1797 bool added = true; 1798 1799 if(!_end.index!N.left) 1800 { 1801 _end.index!N.left = n; 1802 } 1803 else 1804 { 1805 Node newParent = _end.index!N.left; 1806 Node nxt = void; 1807 auto k = key(n.value); 1808 while(true) 1809 { 1810 auto pk = key(newParent.value); 1811 if(_less(k, pk)) 1812 { 1813 nxt = newParent.index!N.left; 1814 if(nxt is null) 1815 { 1816 // 1817 // add to right of new parent 1818 // 1819 newParent.index!N.left = n; 1820 break; 1821 } 1822 } 1823 else 1824 { 1825 static if(!allowDuplicates) 1826 { 1827 if(!_less(pk, k)) 1828 { 1829 added = false; 1830 break; 1831 } 1832 } 1833 nxt = newParent.index!N.right; 1834 if(nxt is null) 1835 { 1836 // 1837 // add to right of new parent 1838 // 1839 newParent.index!N.right = n; 1840 break; 1841 } 1842 } 1843 newParent = nxt; 1844 } 1845 } 1846 1847 static if(allowDuplicates) 1848 { 1849 n.index!N.setColor(_end); 1850 version(RBDoChecks) _Check(); 1851 return added; 1852 } 1853 else 1854 { 1855 if(added) 1856 n.index!N.setColor(_end); 1857 version(RBDoChecks) _Check(); 1858 return added; 1859 } 1860 } 1861 1862 /** 1863 * Element type for the tree 1864 */ 1865 alias ValueView Elem; 1866 1867 Node _end; 1868 1869 static if(!allowDuplicates){ 1870 bool _DenyInsertion(Node n, out Node cursor){ 1871 return _find2(key(n.value), cursor); 1872 } 1873 } 1874 1875 static if(allowDuplicates) alias _add _Insert; 1876 else void _Insert(Node n, Node cursor){ 1877 if(cursor !is null){ 1878 if (_less(key(n.value), key(cursor.value))){ 1879 cursor.index!N.left = n; 1880 }else{ 1881 cursor.index!N.right = n; 1882 } 1883 n.index!N.setColor(_end); 1884 }else{ 1885 _add(n); 1886 } 1887 1888 } 1889 1890 1891 // if k exists in this index, returns par such that eq(key(par.value),k), 1892 // and returns true 1893 // if k !exists in this index, returns par such that k value belongs either 1894 // as par.left or par.right. remember to setColor! returns false. 1895 private bool _find2(KeyType k, out inout(ThisNode)* par) inout 1896 { 1897 auto cur = _end.index!N.left; 1898 par = null; 1899 while(cur) 1900 { 1901 // BAD!!! TODO: figure out unaryFun & inout 1902 auto ck = key(cast() cur.value); 1903 par = cur; 1904 if(_less(ck, k)){ 1905 cur = cur.index!N.right; 1906 }else if(_less(k, ck)){ 1907 cur = cur.index!N.left; 1908 }else{ 1909 return true; 1910 } 1911 } 1912 return false; 1913 } 1914 1915 private bool _find2At(KeyType k, Node cur, out Node par) 1916 { 1917 par = null; 1918 while(cur) 1919 { 1920 auto ck = key(cur.value); 1921 par = cur; 1922 if(_less(ck, k)){ 1923 cur = cur.index!N.right; 1924 }else if(_less(k, ck)){ 1925 cur = cur.index!N.left; 1926 }else{ 1927 return true; 1928 } 1929 } 1930 return false; 1931 } 1932 1933 /** 1934 * Check if any elements exist in the container. Returns $(D true) if at least 1935 * one element exists. 1936 * Complexity: $(BIGOH 1) 1937 */ 1938 @property bool empty() const 1939 { 1940 return node_count == 0; 1941 } 1942 1943 /++ 1944 Returns the number of elements in the container. 1945 1946 Complexity: $(BIGOH 1). 1947 +/ 1948 @property size_t length() const 1949 { 1950 return node_count; 1951 } 1952 1953 /** 1954 * Fetch a range that spans all the elements in the container. 1955 * 1956 * Complexity: $(BIGOH log(n)) 1957 */ 1958 OrderedRange opSlice() 1959 { 1960 return OrderedRange(this,_end.index!N.leftmost, _end); 1961 } 1962 1963 ConstOrderedRange opSlice() const{ 1964 return ConstOrderedRange(this,_end.index!N.leftmost, _end); 1965 } 1966 1967 /** 1968 * The front element in the container 1969 * 1970 * Complexity: $(BIGOH log(n)) 1971 */ 1972 @property front() inout 1973 { 1974 return _end.index!N.leftmost.value; 1975 } 1976 1977 /** 1978 * The last element in the container 1979 * 1980 * Complexity: $(BIGOH log(n)) 1981 */ 1982 @property back() inout 1983 { 1984 return _end.index!N.prev.value; 1985 } 1986 1987 /++ 1988 $(D in) operator. Check to see if the given element exists in the 1989 container. 1990 1991 Complexity: $(BIGOH log(n)) 1992 +/ 1993 bool opBinaryRight(string op)(Elem e) const 1994 if (op == "in") 1995 { 1996 const(ThisNode)* p; 1997 return _find2(key(e),p); 1998 } 1999 /++ 2000 $(D in) operator. Check to see if the given element exists in the 2001 container. 2002 2003 Complexity: $(BIGOH log(n)) 2004 +/ 2005 static if(!isImplicitlyConvertible!(KeyType, Elem)){ 2006 bool opBinaryRight(string op,K)(K k) if (op == "in" && 2007 isImplicitlyConvertible!(K, KeyType)) 2008 { 2009 Node p; 2010 return _find2(k,p); 2011 } 2012 } 2013 2014 void _ClearIndex() { 2015 _end.index!N._left = null; 2016 } 2017 2018 /** 2019 * Removes all elements from the container. 2020 * 2021 * Complexity: ?? 2022 */ 2023 void clear() 2024 { 2025 _Clear(); 2026 } 2027 2028 static if(!allowDuplicates){ 2029 /** 2030 Available for Unique variant. 2031 Complexity: 2032 $(BIGOH log(n)) 2033 */ 2034 ValueView opIndex(KeyType k) inout{ 2035 inout(ThisNode)* n; 2036 enforce(_find2(k,n)); 2037 return cast(ValueView) n.value; 2038 } 2039 } 2040 2041 /** 2042 Perform mod on r.front and performs any necessary fixups to container's 2043 indices. If the result of mod violates any index' invariant, r.front is 2044 removed from the container. 2045 Preconditions: !r.empty, $(BR) 2046 mod is a callable of the form void mod(ref Value) 2047 Complexity: $(BIGOH m(n)), $(BR) $(BIGOH log(n)) for this index 2048 */ 2049 2050 void modify(SomeRange, Modifier)(SomeRange r, Modifier mod) 2051 if(is(SomeRange == OrderedRange) || 2052 is(ElementType!SomeRange == Position!ThisNode)) { 2053 while(!r.empty) { 2054 static if(is(SomeRange == OrderedRange)) { 2055 Node node = r.front_node; 2056 }else { 2057 Node node = r.front.node; 2058 } 2059 r.popFront(); 2060 _Modify(node, mod); 2061 } 2062 } 2063 /** 2064 Replaces r.front with value 2065 Returns: whether replacement succeeded 2066 Complexity: ?? 2067 */ 2068 bool replace(Position!ThisNode r, ValueView value) { 2069 return _Replace(r.node, cast(Value) value); 2070 } 2071 2072 KeyType _NodePosition(ThisNode* node){ 2073 return key(node.value); 2074 } 2075 2076 // cursor = null -> no fixup needed 2077 // cursor != null -> fixup needed 2078 bool _PositionFixable(ThisNode* node, KeyType oldPosition, 2079 out ThisNode* cursor){ 2080 cursor = null; 2081 // case 1: key hasn't changed 2082 auto newPosition = key(node.value); 2083 if(!_less(newPosition, oldPosition) && 2084 !_less(oldPosition, newPosition)) return true; 2085 Node next = _end.index!N.rightmost is node ? null : node.index!N.next; 2086 auto prev = _end.index!N.leftmost is node ? null : node.index!N.prev; 2087 2088 // case 2: key has changed, but relative position hasn't 2089 bool outOfBounds = (next && next != _end && 2090 !_less(newPosition, key(next.value))) || 2091 prev && !_less(key(prev.value), newPosition); 2092 if (!outOfBounds) return true; 2093 2094 // case 3: key has changed, position has changed 2095 static if(allowDuplicates){ 2096 cursor = node; 2097 return true; 2098 }else{ 2099 bool found = _find2(newPosition, cursor); 2100 if(cursor is node){ 2101 // node's old value is in path to node's new value 2102 if(_less(newPosition, oldPosition)){ 2103 if(cursor.index!N._left){ 2104 found = _find2At(newPosition, 2105 cursor.index!N._left, cursor); 2106 }else{ 2107 found = false; 2108 } 2109 }else{ 2110 if(cursor.index!N._right){ 2111 found = _find2At(newPosition, 2112 cursor.index!N._right, cursor); 2113 }else{ 2114 found = false; 2115 } 2116 } 2117 } 2118 return !found; 2119 } 2120 } 2121 2122 void _FixPosition(ThisNode* node, KeyType oldPosition, ThisNode* cursor) 2123 out{ 2124 version(RBDoChecks) _Check(); 2125 }body{ 2126 static if(allowDuplicates){ 2127 if(cursor){ 2128 _Remove(node); 2129 node.index!N._parent = 2130 node.index!N._left = 2131 node.index!N._right = null; 2132 node.index!N.color = Color.Red; 2133 _Insert(node); 2134 } 2135 }else{ 2136 if(!cursor) return; 2137 _Remove(node); 2138 node.index!N._parent = 2139 node.index!N._left = 2140 node.index!N._right = null; 2141 node.index!N.color = Color.Red; 2142 _Insert(node, cursor); 2143 } 2144 } 2145 2146 // n's value has changed and its position might be invalid. 2147 // remove n if it violates an invariant. 2148 // returns: true iff n's validity has been restored 2149 bool _NotifyChange(Node node) 2150 out(r){ 2151 _Check(); 2152 }body{ 2153 auto newPosition = key(node.value); 2154 Node next = _end.index!N.rightmost is node ? null : node.index!N.next; 2155 Node prev = _end.index!N.leftmost is node ? null : node.index!N.prev; 2156 2157 // case 1: key has changed, but relative position hasn't 2158 bool outOfBounds = (next && next != _end && 2159 !_less(newPosition, key(next.value))) || 2160 prev && !_less(key(prev.value), newPosition); 2161 if (!outOfBounds) return true; 2162 2163 // case 2: key has changed, position has changed 2164 static if(allowDuplicates){ 2165 _Remove(node); 2166 node.index!N._parent = 2167 node.index!N._left = 2168 node.index!N._right = null; 2169 node.index!N.color = Color.Red; 2170 _Insert(node); 2171 return true; 2172 }else{ 2173 Node cursor; 2174 _Remove(node); 2175 bool found = _find2(newPosition, cursor); 2176 if(found){ 2177 _RemoveAllBut!N(node); 2178 return false; 2179 } 2180 node.index!N._parent = 2181 node.index!N._left = 2182 node.index!N._right = null; 2183 node.index!N.color = Color.Red; 2184 _Insert(node, cursor); 2185 return true; 2186 } 2187 } 2188 2189 /** 2190 * Insert a single element in the container. Note that this does not 2191 * invalidate any ranges currently iterating the container. 2192 * 2193 * Complexity: $(BIGOH i(n)); $(BR) $(BIGOH log(n)) for this index 2194 */ 2195 size_t insert(Stuff)(Stuff stuff) 2196 if (isImplicitlyConvertible!(Stuff, Elem)) 2197 out(r){ 2198 version(RBDoChecks) _Check(); 2199 }body{ 2200 static if(!allowDuplicates){ 2201 Node p; 2202 if(_find2(key(stuff),p)){ 2203 return 0; 2204 } 2205 } 2206 Node n = _InsertAllBut!N(stuff); 2207 if(!n) return 0; 2208 static if(!allowDuplicates){ 2209 _Insert(n,p); 2210 }else _add(n); 2211 return 1; 2212 } 2213 2214 /** 2215 * Insert a range of elements in the container. Note that this does not 2216 * invalidate any ranges currently iterating the container. 2217 * 2218 * Complexity: $(BIGOH n $(SUB stuff) * i(n)); $(BR) $(BIGOH n $(SUB 2219 stuff) * log(n)) for this index 2220 */ 2221 size_t insert(Stuff)(Stuff stuff) 2222 if(isInputRange!Stuff && 2223 isImplicitlyConvertible!(ElementType!Stuff, Elem)) 2224 out(r){ 2225 version(RBDoChecks) _Check(); 2226 }body{ 2227 size_t result = 0; 2228 foreach(e; stuff) 2229 { 2230 result += insert(e); 2231 } 2232 return result; 2233 } 2234 2235 Node _Remove(Node n) 2236 out(r){ 2237 version(RBDoChecks) _Check(); 2238 }body{ 2239 return n.index!N.remove(_end); 2240 } 2241 2242 /** 2243 * Remove an element from the container and return its value. 2244 * 2245 * Complexity: $(BIGOH d(n)); $(BR) $(BIGOH log(n)) for this index 2246 */ 2247 Elem removeAny() { 2248 auto n = _end.index!N.leftmost; 2249 auto result = n.value; 2250 _RemoveAll(n); 2251 return result; 2252 } 2253 2254 /** 2255 * Remove the front element from the container. 2256 * 2257 * Complexity: $(BIGOH d(n)); $(BR) $(BIGOH log(n)) for this index 2258 */ 2259 void removeFront() { 2260 auto n = _end.index!N.leftmost; 2261 _RemoveAll(n); 2262 } 2263 2264 /** 2265 * Remove the back element from the container. 2266 * 2267 * Complexity: $(BIGOH d(n)); $(BR) $(BIGOH log(n)) for this index 2268 */ 2269 void removeBack() { 2270 auto n = _end.index!N.prev; 2271 _RemoveAll(n); 2272 } 2273 2274 /++ 2275 Removes the given range from the container. 2276 2277 Returns: A range containing all of the elements that were after the 2278 given range. 2279 2280 Complexity:$(BIGOH n $(SUB r) * d(n)); $(BR) $(BIGOH n $(SUB r) * 2281 log(n)) for this index 2282 +/ 2283 OrderedRange remove(R)(R r) 2284 if(is(R == OrderedRange) || 2285 is(ElementType!R == Position!ThisNode)) 2286 out(r){ 2287 version(RBDoChecks) _Check(); 2288 }body{ 2289 while(!r.empty) { 2290 static if(is(R == OrderedRange)) { 2291 auto node = r.front_node; 2292 }else{ 2293 auto node = r.front.node; 2294 r.front.obliterated = true; 2295 } 2296 r.popFront(); 2297 _RemoveAll!N(node); 2298 } 2299 return OrderedRange(this, _end, _end); 2300 } 2301 2302 /++ 2303 Removes elements from the container that are equal to the given values 2304 according to the less comparator. One element is removed for each value 2305 given which is in the container. If $(D allowDuplicates) is true, 2306 duplicates are removed only if duplicate values are given. 2307 2308 Returns: The number of elements removed. 2309 2310 Complexity: $(BIGOH n $(SUB keys) d(n)); $(BR) $(BIGOH n 2311 $(SUB keys) log(n)) for this index 2312 2313 Examples: 2314 -------------------- 2315 // ya, this needs updating 2316 auto rbt = redBlackTree!true(0, 1, 1, 1, 4, 5, 7); 2317 rbt.removeKey(1, 4, 7); 2318 assert(std.algorithm.equal(rbt[], [0, 1, 1, 5])); 2319 rbt.removeKey(1, 1, 0); 2320 assert(std.algorithm.equal(rbt[], [5])); 2321 -------------------- 2322 +/ 2323 size_t removeKey(Keys...)(Keys keys) 2324 if(allSatisfy!(implicitlyConverts,Keys)) 2325 out(r){ 2326 version(RBDoChecks) _Check(); 2327 }body{ 2328 // stack allocation - is ok 2329 Unqual!KeyType[Keys.length] toRemove; 2330 foreach(i,k; keys) { 2331 Unqual!KeyType k2 = k; 2332 move(k2, toRemove[i]); 2333 } 2334 2335 return removeKey(cast(KeyType[])(toRemove[])); 2336 } 2337 2338 size_t removeKey(Key)(Key[] keys) 2339 if(isImplicitlyConvertible!(Key, KeyType)) 2340 out(r){ 2341 version(RBDoChecks) _Check(); 2342 }body{ 2343 size_t count = 0; 2344 2345 foreach(k; keys) 2346 { 2347 auto beg = _firstGreaterEqual(k); 2348 if(beg is _end || _less(k, key(beg.value))) 2349 // no values are equal 2350 continue; 2351 _RemoveAll(beg); 2352 count++; 2353 } 2354 2355 return count; 2356 } 2357 2358 private template implicitlyConverts(Key){ 2359 enum implicitlyConverts = isImplicitlyConvertible!(Key,KeyType); 2360 } 2361 2362 /++ Ditto +/ 2363 size_t removeKey(Stuff)(Stuff stuff) 2364 if(isInputRange!Stuff && 2365 isImplicitlyConvertible!(ElementType!Stuff, KeyType) && 2366 !isDynamicArray!Stuff) 2367 out(r){ 2368 version(RBDoChecks) _Check(); 2369 }body{ 2370 //We use array in case stuff is a Range from this RedBlackTree - either 2371 //directly or indirectly. 2372 2373 alias ElementType!Stuff E; 2374 2375 auto stuffy = allocatedArray!Allocator(stuff); 2376 auto res = removeKey(stuffy); 2377 Allocator.deallocate(stuffy.ptr); 2378 return res; 2379 } 2380 2381 // find the first node where the value is > k 2382 private inout(ThisNode)* _firstGreater(U)(U k) inout 2383 if(isImplicitlyConvertible!(U, KeyType)) 2384 { 2385 // can't use _find, because we cannot return null 2386 typeof(return) cur = _end.index!N.left; 2387 typeof(return) result = _end; 2388 while(cur) 2389 { 2390 // TODO: figure out unaryFun & inout 2391 if(_less(k, key(cast() cur.value))) 2392 { 2393 result = cur; 2394 cur = cur.index!N.left; 2395 } 2396 else 2397 cur = cur.index!N.right; 2398 } 2399 return result; 2400 } 2401 private inout(ThisNode)* 2402 _firstGreater(CompatibleLess, CompatibleKey) 2403 (CompatibleKey k) inout { 2404 // can't use _find, because we cannot return null 2405 typeof(return) cur = _end.index!N.left; 2406 typeof(return) result = _end; 2407 while(cur) 2408 { 2409 // TODO: figure out unaryFun & inout 2410 if(CompatibleLess.ck_less(k, key(cast() cur.value))) 2411 { 2412 result = cur; 2413 cur = cur.index!N.left; 2414 } 2415 else 2416 cur = cur.index!N.right; 2417 } 2418 return result; 2419 } 2420 2421 // find the first node where the value is >= k 2422 private inout(ThisNode)* _firstGreaterEqual(U)(U k) inout 2423 if(isImplicitlyConvertible!(U, KeyType)) 2424 { 2425 // can't use _find, because we cannot return null. 2426 typeof(return) cur = _end.index!N.left; 2427 typeof(return) result = _end; 2428 while(cur) 2429 { 2430 // TODO: figure out unaryFun & inout 2431 if(_less(key(cast() cur.value), k)) 2432 cur = cur.index!N.right; 2433 else 2434 { 2435 result = cur; 2436 cur = cur.index!N.left; 2437 } 2438 2439 } 2440 return result; 2441 } 2442 2443 // find the first node where the value is >= k 2444 private inout(ThisNode)* 2445 _firstGreaterEqual(CompatibleLess, CompatibleKey) 2446 (CompatibleKey k) inout { 2447 // can't use _find, because we cannot return null. 2448 typeof(return) cur = _end.index!N.left; 2449 typeof(return) result = _end; 2450 while(cur) 2451 { 2452 // TODO: figure out unaryFun & inout 2453 if(CompatibleLess.kc_less(key(cast() cur.value), k)) 2454 cur = cur.index!N.right; 2455 else 2456 { 2457 result = cur; 2458 cur = cur.index!N.left; 2459 } 2460 2461 } 2462 return result; 2463 } 2464 2465 /** 2466 * Get a range from the container with all elements that are > k according 2467 * to the less comparator 2468 * 2469 * Complexity: $(BIGOH log(n)) 2470 */ 2471 auto upperBound(U)(U k) 2472 if(isImplicitlyConvertible!(U, KeyType)) 2473 { 2474 return OrderedRange(this,_firstGreater(k), _end); 2475 } 2476 auto upperBound(U)(U k) const 2477 if(isImplicitlyConvertible!(U, KeyType)) 2478 { 2479 return ConstOrderedRange(this,_firstGreater(k), _end); 2480 } 2481 auto upperBound(CompatibleLess, CompatibleKey)(CompatibleKey k) 2482 { 2483 return OrderedRange(this,_firstGreater!CompatibleLess(k), _end); 2484 } 2485 auto upperBound(CompatibleLess, CompatibleKey)(CompatibleKey k) const 2486 { 2487 return ConstOrderedRange(this,_firstGreater!CompatibleLess(k), _end); 2488 } 2489 2490 /** 2491 * Get a range from the container with all elements that are < k according 2492 * to the less comparator 2493 * 2494 * Complexity: $(BIGOH log(n)) 2495 */ 2496 auto lowerBound(U)(U k) 2497 if(isImplicitlyConvertible!(U, KeyType)) 2498 { 2499 return OrderedRange(this,_end.index!N.leftmost, _firstGreaterEqual(k)); 2500 } 2501 auto lowerBound(U)(U k) const 2502 if(isImplicitlyConvertible!(U, KeyType)) 2503 { 2504 return ConstOrderedRange(this,_end.index!N.leftmost, _firstGreaterEqual(k)); 2505 } 2506 2507 auto lowerBound(CompatibleLess, CompatibleKey)(CompatibleKey k) 2508 { 2509 return OrderedRange(this,_end.index!N.leftmost, 2510 _firstGreaterEqual!CompatibleLess(k)); 2511 } 2512 auto lowerBound(CompatibleLess, CompatibleKey)(CompatibleKey k) const 2513 { 2514 return ConstOrderedRange(this,_end.index!N.leftmost, 2515 _firstGreaterEqual!CompatibleLess(k)); 2516 } 2517 2518 /** 2519 * Get a range from the container with all elements that are == k according 2520 * to the less comparator 2521 * 2522 * Complexity: $(BIGOH log(n)) 2523 */ 2524 // TODO: compact these back into one 2525 auto equalRange(U)(U k) 2526 if(isImplicitlyConvertible!(U, KeyType)) 2527 { 2528 auto beg = _firstGreaterEqual(k); 2529 if(beg is _end || _less(k, key(beg.value))) 2530 // no values are equal 2531 return OrderedRange(this,beg, beg); 2532 static if(allowDuplicates) 2533 { 2534 return OrderedRange(this,beg, _firstGreater(k)); 2535 } 2536 else 2537 { 2538 // no sense in doing a full search, no duplicates are allowed, 2539 // so we just get the next node. 2540 return OrderedRange(this,beg, beg.index!N.next); 2541 } 2542 } 2543 auto equalRange(U)(U k) const 2544 if(isImplicitlyConvertible!(U, KeyType)) 2545 { 2546 auto beg = _firstGreaterEqual(k); 2547 if(beg is _end || _less(k, key(beg.value))) 2548 // no values are equal 2549 return ConstOrderedRange(this,beg, beg); 2550 static if(allowDuplicates) 2551 { 2552 return ConstOrderedRange(this,beg, _firstGreater(k)); 2553 } 2554 else 2555 { 2556 // no sense in doing a full search, no duplicates are allowed, 2557 // so we just get the next node. 2558 return ConstOrderedRange(this,beg, beg.index!N.next); 2559 } 2560 } 2561 2562 // @@@BUG@@@ dmd issue 8440 prevents us frem naming this function equalRange 2563 OrderedRange cEqualRange(CompatibleLess, CompatibleKey)(CompatibleKey k) 2564 if(IsCompatibleLess!(CompatibleLess, KeyType, CompatibleKey)) 2565 { 2566 auto beg = _firstGreaterEqual!CompatibleLess(k); 2567 if(beg is _end || CompatibleLess.ck_less(k, key(beg.value))) 2568 // no values are equal 2569 return OrderedRange(this,beg, beg); 2570 return OrderedRange(this,beg, _firstGreater!CompatibleLess(k)); 2571 } 2572 ConstOrderedRange cEqualRange(CompatibleLess, CompatibleKey)(CompatibleKey k) const 2573 if(IsCompatibleLess!(CompatibleLess, KeyType, CompatibleKey)) 2574 { 2575 auto beg = _firstGreaterEqual!CompatibleLess(k); 2576 if(beg is _end || CompatibleLess.ck_less(k, key(beg.value))) 2577 // no values are equal 2578 return ConstOrderedRange(this,beg, beg); 2579 return ConstOrderedRange(this,beg, _firstGreater!CompatibleLess(k)); 2580 } 2581 2582 /++ 2583 Get a range of values bounded below by lower and above by upper, with 2584 inclusiveness defined by boundaries. 2585 Complexity: $(BIGOH log(n)) 2586 +/ 2587 auto bounds(string boundaries = "[]", U)(U lower, U upper) 2588 if(isImplicitlyConvertible!(U, KeyType)) 2589 in{ 2590 static if(boundaries == "[]") assert(!_less(upper,lower), 2591 format("nonsensical bounds %s%s,%s%s", 2592 boundaries[0], lower, upper, boundaries[1])); 2593 else assert(_less(lower,upper), 2594 format("nonsensical bounds %s%s,%s%s", 2595 boundaries[0], lower, upper, boundaries[1])); 2596 }body{ 2597 static if(boundaries[0] == '[') { 2598 auto n_lower = _firstGreaterEqual(lower); 2599 }else static if(boundaries[0] == '('){ 2600 auto n_lower = _firstGreater(lower); 2601 }else static assert(false); 2602 static if(boundaries[1] == ']') { 2603 auto n_upper = _firstGreater(upper); 2604 }else static if(boundaries[1] == ')'){ 2605 auto n_upper = _firstGreaterEqual(upper); 2606 }else static assert(false); 2607 return OrderedRange(this, n_lower, n_upper); 2608 } 2609 2610 auto cbounds(CompatibleLess,string boundaries = "[]", CompatibleKey) 2611 (CompatibleKey lower, CompatibleKey upper) 2612 if(IsCompatibleLess!(CompatibleLess, KeyType, CompatibleKey)) 2613 in{ 2614 static if(boundaries == "[]") 2615 assert(!CompatibleLess.cc_less(upper,lower), 2616 format("nonsensical bounds %s%s,%s%s", 2617 boundaries[0], lower, upper, boundaries[1])); 2618 else assert(CompatibleLess.cc_less(lower,upper), 2619 format("nonsensical bounds %s%s,%s%s", 2620 boundaries[0], lower, upper, boundaries[1])); 2621 }body{ 2622 static if(boundaries[0] == '[') { 2623 auto n_lower = _firstGreaterEqual!CompatibleLess(lower); 2624 }else static if(boundaries[0] == '('){ 2625 auto n_lower = _firstGreater!CompatibleLess(lower); 2626 }else static assert(false); 2627 static if(boundaries[1] == ']') { 2628 auto n_upper = _firstGreater!CompatibleLess(upper); 2629 }else static if(boundaries[1] == ')'){ 2630 auto n_upper = _firstGreaterEqual!CompatibleLess(upper); 2631 }else static assert(false); 2632 return OrderedRange(this, n_lower, n_upper); 2633 } 2634 2635 /* 2636 * Print the tree. This prints a sideways view of the tree in ASCII form, 2637 * with the number of indentations representing the level of the nodes. 2638 * It does not print values, only the tree structure and color of nodes. 2639 */ 2640 void printTree(Node n, int indent = 0) 2641 { 2642 if(n !is null) 2643 { 2644 printTree(n.index!N.right, indent + 2); 2645 for(int i = 0; i < indent; i++) 2646 write("."); 2647 write(n.index!N.color == Color.Black ? "B" : "R"); 2648 writefln("(%s)", n.value); 2649 printTree(n.index!N.left, indent + 2); 2650 } 2651 else 2652 { 2653 for(int i = 0; i < indent; i++) 2654 write("."); 2655 writeln("N"); 2656 } 2657 if(indent is 0) 2658 writeln(); 2659 } 2660 void _NodeReplace(ThisNode* old, ThisNode* newnode) { 2661 ThisNode* lch = old.index!N.left; 2662 ThisNode* rch = old.index!N.right; 2663 ThisNode* p = old.index!N.parent; 2664 2665 newnode.index!N.left = lch; 2666 if(lch) { 2667 lch.index!N._parent = newnode; 2668 } 2669 newnode.index!N.right = rch; 2670 if(rch) { 2671 rch.index!N._parent = newnode; 2672 } 2673 newnode.index!N._parent = p; 2674 if(p) { 2675 if(p.index!N.left is old) { 2676 p.index!N.left = newnode; 2677 }else if(p.index!N.right is old) { 2678 p.index!N.right = newnode; 2679 } 2680 }else if(old is _end) { 2681 _end = newnode; 2682 } 2683 2684 newnode.index!N.left = null; 2685 newnode.index!N.right = null; 2686 newnode.index!N._parent = null; 2687 } 2688 2689 2690 /* 2691 * Check the tree for validity. This is called after every add or remove. 2692 * This should only be enabled to debug the implementation of the RB Tree. 2693 */ 2694 void _Check() 2695 { 2696 // 2697 // check implementation of the tree 2698 // 2699 int recurse(Node n, string path) 2700 { 2701 if(n is null) 2702 return 1; 2703 if(n.index!N.parent.index!N.left !is n && n.index!N.parent.index!N.right !is n) 2704 // memory allocation! ..how to fix? 2705 throw new Exception("Node at path " ~ path ~ " has inconsistent pointers"); 2706 Node next = n.index!N.next; 2707 static if(allowDuplicates) 2708 { 2709 if(next !is _end && _less(key(next.value), key(n.value))) 2710 // memory allocation! ..how to fix? 2711 throw new Exception("ordering invalid at path " ~ path); 2712 } 2713 else 2714 { 2715 if(next !is _end && !_less(key(n.value), key(next.value))) 2716 // memory allocation! ..how to fix? 2717 throw new Exception("ordering invalid at path " ~ path); 2718 } 2719 if(n.index!N.color == Color.Red) 2720 { 2721 if((n.index!N.left !is null && n.index!N.left.index!N.color == Color.Red) || 2722 (n.index!N.right !is null && n.index!N.right.index!N.color == Color.Red)) 2723 // memory allocation! ..how to fix? 2724 throw new Exception("Node at path " ~ path ~ " is red with a red child"); 2725 } 2726 2727 int l = recurse(n.index!N.left, path ~ "L"); 2728 int r = recurse(n.index!N.right, path ~ "R"); 2729 if(l != r) 2730 { 2731 writeln("bad tree at:"); 2732 printTree(n); 2733 // memory allocation! ..how to fix? 2734 throw new Exception("Node at path " ~ path ~ " has different number of black nodes on left and right paths"); 2735 } 2736 return l + (n.index!N.color == Color.Black ? 1 : 0); 2737 } 2738 2739 try 2740 { 2741 recurse(_end.index!N.left, ""); 2742 } 2743 catch(Exception e) 2744 { 2745 printTree(_end.index!N.left, 0); 2746 throw e; 2747 } 2748 } 2749 2750 string toString0(){ 2751 string r = "["; 2752 auto rng = opSlice(); 2753 while(!rng.empty){ 2754 r ~= format("%s", (rng.front)); 2755 rng.popFront(); 2756 r ~= rng.empty ? "]" : ", "; 2757 } 2758 return r; 2759 } 2760 2761 private OrderedRange fromNode(ThisNode* n){ 2762 return OrderedRange(this,n, this.index!N._end); 2763 } 2764 } 2765 2766 /// A red black tree index 2767 template Ordered(bool allowDuplicates = false, alias KeyFromValue="a", 2768 alias Compare = "a<b") { 2769 2770 enum bool BenefitsFromSignals = true; 2771 2772 template Inner(ThisContainer, ThisNode, Value, ValueView, size_t N, Allocator){ 2773 alias TypeTuple!(N, allowDuplicates, KeyFromValue, Compare,ThisContainer) IndexTuple; 2774 alias OrderedIndex IndexMixin; 2775 2776 enum IndexCtorMixin = Replace!(q{ 2777 index!($N)._end = Allocator.allocate!ThisNode(1); 2778 }, "$N", N); 2779 /// node implementation (ish) 2780 alias TypeTuple!(N) NodeTuple; 2781 alias OrderedNodeMixin NodeMixin; 2782 } 2783 } 2784 2785 /// A red black tree index 2786 template OrderedNonUnique(alias KeyFromValue="a", alias Compare = "a<b") { 2787 alias Ordered!(true, KeyFromValue, Compare) OrderedNonUnique; 2788 } 2789 /// A red black tree index 2790 template OrderedUnique(alias KeyFromValue="a", alias Compare = "a<b") { 2791 alias Ordered!(false, KeyFromValue, Compare) OrderedUnique; 2792 } 2793 2794 // end RBTree impl 2795 2796 /// a max heap index 2797 template Heap(alias KeyFromValue = "a", alias Compare = "a<b") { 2798 // this index allocates the heap array 2799 2800 enum bool BenefitsFromSignals = true; 2801 2802 /// _ 2803 template Inner(ThisContainer, ThisNode, Value, ValueView, size_t N, Allocator) { 2804 alias TypeTuple!() NodeTuple; 2805 alias TypeTuple!(N,KeyFromValue, Compare, ThisContainer) IndexTuple; 2806 2807 mixin template NodeMixin(){ 2808 size_t _index; 2809 } 2810 2811 /// index implementation 2812 mixin template IndexMixin(size_t N, alias KeyFromValue, alias Compare, 2813 ThisContainer){ 2814 alias unaryFun!KeyFromValue key; 2815 alias binaryFun!Compare less; 2816 alias typeof(key((Value).init)) KeyType; 2817 2818 /// The primary range of the index, which embodies a bidirectional 2819 /// range. 2820 /// 2821 /// Ends up performing a breadth first traversal (I think..) 2822 /// 2823 /// removeFront and removeBack are not possible. 2824 struct HeapRangeT(bool is_const) { 2825 static if(is_const) { 2826 alias const(ThisNode) Node; 2827 alias const(ThisContainer) Container; 2828 }else { 2829 alias ThisContainer Container; 2830 alias ThisNode Node; 2831 } 2832 Container c; 2833 size_t s,e; 2834 2835 this(Container _c, size_t _s, size_t _e) { 2836 c = _c; 2837 s = _s; 2838 e = _e; 2839 } 2840 2841 @property Node* front_node() { 2842 return c.index!N._heap[s]; 2843 } 2844 2845 @property front(){ 2846 return front_node.value; 2847 } 2848 2849 void popFront(){ 2850 s++; 2851 } 2852 2853 @property back_node(){ 2854 return c.index!N._heap[e-1]; 2855 } 2856 2857 @property back(){ 2858 return back_node.value; 2859 } 2860 void popBack(){ 2861 e--; 2862 } 2863 2864 @property bool empty()const{ 2865 assert(e <= c.index!N.length); 2866 return s >= c.index!N.length; 2867 } 2868 @property size_t length()const{ 2869 assert(e <= c.index!N.length); 2870 return s <= e ? e - s : 0; 2871 } 2872 2873 @property save(){ return this; } 2874 } 2875 2876 alias HeapRangeT!true ConstHeapRange; 2877 alias HeapRangeT!false HeapRange; 2878 2879 template IsMyRange(T) { 2880 enum bool IsMyRange = 2881 is(T == ConstHeapRange) || 2882 is(T == HeapRange); 2883 } 2884 2885 ThisNode*[] _heap; 2886 2887 static size_t p(size_t n) pure{ 2888 return (n-1) / 2; 2889 } 2890 2891 static size_t l(size_t n) pure{ 2892 return 2*n + 1; 2893 } 2894 2895 static size_t r(size_t n) pure{ 2896 return 2*n + 2; 2897 } 2898 2899 void swapAt(size_t n1, size_t n2){ 2900 swap(_heap[n1].index!N._index, _heap[n2].index!N._index); 2901 swap(_heap[n1], _heap[n2]); 2902 } 2903 2904 void sift(size_t n){ 2905 auto k = key(_heap[n].value); 2906 if(n > 0 && less(key(_heap[p(n)].value), k)){ 2907 do{ 2908 swapAt(n, p(n)); 2909 n = p(n); 2910 }while(n > 0 && less(key(_heap[p(n)].value), k)); 2911 }else 2912 while(l(n) < node_count){ 2913 auto ch = l(n); 2914 auto lk = key(_heap[ch].value); 2915 if(!less(k, lk)) break; 2916 if (r(n) < node_count){ 2917 auto rk = key(_heap[r(n)].value); 2918 if(less(lk, rk)){ 2919 if(!less(k, rk)) break; 2920 ch = r(n); 2921 } 2922 } 2923 swapAt(n, ch); 2924 n = ch; 2925 } 2926 } 2927 2928 /** 2929 Fetch a range that spans all the elements in the container. 2930 2931 Complexity: $(BIGOH 1) 2932 */ 2933 HeapRange opSlice() { 2934 return HeapRange(this,0, node_count); 2935 } 2936 ConstHeapRange opSlice() const{ 2937 return ConstHeapRange(this,0, node_count); 2938 } 2939 2940 /** 2941 Returns the number of elements in the container. 2942 2943 Complexity: $(BIGOH 1). 2944 */ 2945 @property size_t length()const{ 2946 return node_count; 2947 } 2948 2949 /** 2950 Property returning $(D true) if and only if the container has no 2951 elements. 2952 2953 Complexity: $(BIGOH 1) 2954 */ 2955 @property bool empty()const{ 2956 return node_count == 0; 2957 } 2958 2959 /** 2960 Returns: the max element in this index 2961 Complexity: $(BIGOH 1) 2962 */ 2963 @property front() inout{ 2964 return _heap[0].value; 2965 } 2966 /** 2967 Returns: the back of this index 2968 Complexity: $(BIGOH 1) 2969 */ 2970 @property back() inout{ 2971 return _heap[node_count-1].value; 2972 } 2973 2974 void _ClearIndex(){ 2975 fill(_heap, (ThisNode*).init); 2976 } 2977 /** 2978 ?? 2979 */ 2980 void clear(){ 2981 _Clear(); 2982 } 2983 2984 void modify(SomeRange, Modifier)(SomeRange r, Modifier mod) 2985 if(is(SomeRange == HeapRange) || 2986 is(ElementType!SomeRange == Position!ThisNode)) { 2987 while(!r.empty) { 2988 static if(is(SomeRange == HeapRange)) { 2989 ThisNode* node = r.front_node; 2990 }else{ 2991 ThisNode* node = r.front.node; 2992 } 2993 r.popFront(); 2994 _Modify(node, mod); 2995 } 2996 } 2997 2998 bool replace(Position!ThisNode r, ValueView value) 2999 { 3000 return _Replace(r.node, cast(Value) value); 3001 } 3002 3003 KeyType _NodePosition(ThisNode* node){ 3004 return key(node.value); 3005 } 3006 3007 bool _PositionFixable(ThisNode* node, KeyType oldPosition, 3008 out ThisNode* cursor){ 3009 return true; 3010 } 3011 3012 void _FixPosition(ThisNode* node, KeyType oldPosition, 3013 ThisNode* cursor){ 3014 // sift will take O(1) if key hasn't changed 3015 sift(node.index!N._index); 3016 } 3017 3018 bool _NotifyChange(ThisNode* node){ 3019 // sift will take O(1) if key hasn't changed 3020 sift(node.index!N._index); 3021 return true; 3022 } 3023 3024 /** 3025 Returns the _capacity of the index, which is the length of the 3026 underlying store 3027 */ 3028 size_t capacity()const{ 3029 return _heap.length; 3030 } 3031 3032 /** 3033 Ensures sufficient capacity to accommodate $(D n) elements. 3034 3035 Postcondition: $(D capacity >= n) 3036 3037 Complexity: $(BIGOH ??) if $(D e > capacity), 3038 otherwise $(BIGOH 1). 3039 */ 3040 void reserve(size_t count){ 3041 if(_heap.length < count){ 3042 auto newheap = Allocator.allocate!(ThisNode*)(count)[0 .. count]; 3043 auto rest = moveAll(_heap, newheap); 3044 fill(rest, (ThisNode*).init); 3045 Allocator.deallocate(_heap.ptr); 3046 _heap = newheap; 3047 } 3048 } 3049 /** 3050 Inserts value into this heap, unless another index refuses it. 3051 Returns: the number of values added to the container 3052 Complexity: $(BIGOH i(n)); $(BR) $(BIGOH log(n)) for this index 3053 */ 3054 size_t insert(SomeValue)(SomeValue value) 3055 if(isImplicitlyConvertible!(SomeValue, ValueView)) 3056 { 3057 ThisNode* n = _InsertAllBut!N(value); 3058 if(!n) return 0; 3059 node_count--; 3060 _Insert(n); 3061 node_count++; 3062 return 1; 3063 } 3064 3065 size_t insert(SomeRange)(SomeRange r) 3066 if(isImplicitlyConvertible!(ElementType!SomeRange, ValueView)) 3067 { 3068 size_t count; 3069 foreach(e; r){ 3070 count += insert(e); 3071 } 3072 return count; 3073 } 3074 3075 void _Insert(ThisNode* node){ 3076 if(node_count == _heap.length){ 3077 reserve(max(_heap.length*2+1, node_count+1)); 3078 } 3079 _heap[node_count] = node; 3080 _heap[node_count].index!N._index = node_count; 3081 sift(node_count); 3082 } 3083 3084 /** 3085 Removes the max element of this index from the container. 3086 Complexity: $(BIGOH d(n)); $(BR) $(BIGOH log(n)) for this index 3087 */ 3088 void removeFront(){ 3089 _RemoveAll(_heap[0]); 3090 } 3091 3092 void _Remove(ThisNode* node){ 3093 if(node.index!N._index == node_count-1){ 3094 _heap[node_count-1] = null; 3095 }else{ 3096 size_t ix = node.index!N._index; 3097 swapAt(ix, node_count-1); 3098 _heap[node_count-1] = null; 3099 node_count--; 3100 sift(ix); 3101 node_count++; 3102 } 3103 } 3104 /** 3105 Forwards to removeFront 3106 */ 3107 alias removeFront removeAny; 3108 3109 3110 /** 3111 * removes the back of this index from the container. Why would you do this? 3112 No idea. 3113 Complexity: $(BIGOH d(n)); $(BR) $(BIGOH 1) for this index 3114 */ 3115 void removeBack(){ 3116 ThisNode* node = _heap[node_count-1]; 3117 _RemoveAll(node); 3118 } 3119 3120 HeapRange remove(R)(R r) 3121 if (is(R == HeapRange) || 3122 is(ElementType!R == Position!ThisNode)){ 3123 while(!r.empty){ 3124 static if(is(R == HeapRange)){ 3125 ThisNode* node = r.front_node; 3126 }else{ 3127 ThisNode* node = r.front.node; 3128 r.front.obliterated = true; 3129 } 3130 r.popFront(); 3131 _RemoveAll(node); 3132 } 3133 return HeapRange(this,0,0); 3134 } 3135 3136 bool isLe(size_t a, size_t b){ 3137 return(!less(key(_heap[b].value),key(_heap[a].value))); 3138 } 3139 3140 bool _invariant(size_t i){ 3141 bool result = true; 3142 if(i > 0){ 3143 result &= (isLe(i,p(i))); 3144 } 3145 if( l(i) < node_count ){ 3146 result &= (isLe(l(i), i)); 3147 } 3148 if( r(i) < node_count ){ 3149 result &= (isLe(r(i), i)); 3150 } 3151 return result; 3152 } 3153 3154 void _NodeReplace(ThisNode* old, ThisNode* newnode) { 3155 move(newnode, _heap[old.index!N._index]); 3156 newnode.index!N._index = old.index!N._index; 3157 } 3158 3159 void _Check(){ 3160 for(size_t i = 0; i < node_count; i++){ 3161 assert (_heap[i].index!N._index == i); 3162 assert (_invariant(i)); 3163 } 3164 3165 } 3166 3167 void printHeap(){ 3168 printHeap1(0,0); 3169 } 3170 3171 void printHeap1(size_t n, size_t indent){ 3172 if (l(n) < node_count) printHeap1(l(n), indent+1); 3173 for(int i = 0; i < indent; i++) 3174 write(".."); 3175 static if(__traits(compiles, (_heap[n].value.toString0()))){ 3176 writefln("%s (%s) %s", n, _heap[n].value.toString0(), _invariant(n) ? "" : "<--- bad!!!"); 3177 }else{ 3178 writefln("(%s)", _heap[n].value); 3179 } 3180 3181 if (r(n) < node_count) printHeap1(r(n), indent+1); 3182 } 3183 3184 string toString0(){ 3185 string r = "["; 3186 auto rng = opSlice(); 3187 while(!rng.empty){ 3188 r ~= format("%s", (rng.front)); 3189 rng.popFront(); 3190 r ~= rng.empty ? "]" : ", "; 3191 } 3192 return r; 3193 } 3194 3195 private HeapRange fromNode(ThisNode* n){ 3196 return HeapRange(this, n.index!N._index, this.node_count); 3197 } 3198 } 3199 } 3200 } 3201 3202 // thieved from boost::multi_index::detail::bucket_array. 3203 static if(size_t.sizeof == 4){ 3204 immutable size_t[] primes = [ 3205 53u, 97u, 193u, 389u, 769u, 3206 1543u, 3079u, 6151u, 12289u, 24593u, 3207 49157u, 98317u, 196613u, 393241u, 786433u, 3208 1572869u, 3145739u, 6291469u, 12582917u, 25165843u, 3209 50331653u, 100663319u, 201326611u, 402653189u, 805306457u, 3210 1610612741u, 3221225473u, 4294967291u 3211 ]; 3212 }else static if(size_t.sizeof == 8){ 3213 immutable size_t[] primes = [ 3214 53uL, 97uL, 193uL, 389uL, 769uL, 3215 1543uL, 3079uL, 6151uL, 12289uL, 24593uL, 3216 49157uL, 98317uL, 196613uL, 393241uL, 786433uL, 3217 1572869uL, 3145739uL, 6291469uL, 12582917uL, 25165843uL, 3218 50331653uL, 100663319uL, 201326611uL, 402653189uL, 805306457uL, 3219 1610612741uL, 3221225473uL, 4294967291uL, 3220 6442450939uL, 12884901893uL, 25769803751uL, 51539607551uL, 3221 103079215111uL, 206158430209uL, 412316860441uL, 824633720831uL, 3222 1649267441651uL, 3298534883309uL, 6597069766657uL, 13194139533299uL, 3223 26388279066623uL, 52776558133303uL, 105553116266489uL, 3224 211106232532969uL, 3225 422212465066001uL, 844424930131963uL, 1688849860263953uL, 3226 3377699720527861uL, 6755399441055731uL, 13510798882111483uL, 3227 27021597764222939uL, 54043195528445957uL, 108086391056891903uL, 3228 216172782113783843uL, 432345564227567621uL, 864691128455135207uL, 3229 1729382256910270481uL, 3458764513820540933uL, 6917529027641081903uL, 3230 13835058055282163729uL, 18446744073709551557uL 3231 ]; 3232 }else static assert(false, 3233 Replace!("waht is this weird sizeof(size_t) == %s?", "%s",size_t.sizeof)); 3234 3235 /// a hash table index 3236 /// KeyFromValue(value) = key of type KeyType 3237 /// Hash(key) = hash of type size_t 3238 /// Eq(key1, key2) determines equality of key1, key2 3239 template Hashed(bool allowDuplicates = false, alias KeyFromValue="a", 3240 alias Hash="typeid(a).getHash(&a)", alias Eq="a==b") { 3241 // this index allocates the table, and an array in removeKey 3242 3243 enum bool BenefitsFromSignals = true; 3244 3245 /// _ 3246 template Inner(ThisContainer, ThisNode, Value, ValueView, size_t N, Allocator) { 3247 alias unaryFun!KeyFromValue key; 3248 alias typeof(key(Value.init)) KeyType; 3249 3250 alias TypeTuple!(N) NodeTuple; 3251 alias TypeTuple!(N,KeyFromValue, Hash, Eq, allowDuplicates, 3252 Sequenced!().Inner!(ThisContainer, ThisNode,Value,ValueView,N,Allocator).SequencedRange, 3253 ThisContainer) IndexTuple; 3254 // node implementation 3255 // could be singly linked, but that would make aux removal more 3256 // difficult 3257 alias Sequenced!().Inner!(ThisContainer, ThisNode, Value, ValueView,N,Allocator).NodeMixin 3258 NodeMixin; 3259 3260 enum IndexCtorMixin = Replace!(q{ 3261 index!$N .hashes = Allocator.allocate!(ThisNode*)(primes[0])[0 .. primes[0]]; 3262 index!$N .load_factor = 0.80; 3263 }, "$N", N); 3264 3265 /// index implementation 3266 mixin template IndexMixin(size_t N, alias KeyFromValue, alias Hash, 3267 alias Eq, bool allowDuplicates, alias SeqRange, ThisContainer){ 3268 alias unaryFun!KeyFromValue key; 3269 alias typeof(key((Value).init)) KeyType; 3270 alias unaryFun!Hash hash; 3271 alias binaryFun!Eq eq; 3272 alias SeqRange!false BucketSeqRange; 3273 alias SeqRange!true ConstBucketSeqRange; 3274 3275 /// the primary range for this index, which embodies a forward 3276 /// range. iteration has time complexity O(n) 3277 struct HashedRangeT(bool is_const) { 3278 static if(is_const) { 3279 alias const(ThisNode) Node; 3280 alias const(ThisContainer) Container; 3281 }else { 3282 alias ThisContainer Container; 3283 alias ThisNode Node; 3284 } 3285 Container c; 3286 Node* node; 3287 alias node front_node; 3288 size_t n; 3289 3290 this(Container _c, Node* _node, size_t _n) { 3291 c = _c; 3292 node = _node; 3293 n = _n; 3294 } 3295 3296 @property bool empty()/*const*/{ 3297 return n >= c.index!N.hashes.length; 3298 } 3299 3300 @property front() { 3301 return node.value; 3302 } 3303 3304 void popFront(){ 3305 node = node.index!N.next; 3306 if(!node){ 3307 do n++; 3308 while(n < c.index!N.hashes.length && !c.index!N.hashes[n]); 3309 if( n < c.index!N.hashes.length ){ 3310 node = c.index!N.hashes[n]; 3311 } 3312 } 3313 } 3314 3315 @property save(){ 3316 return this; 3317 } 3318 } 3319 3320 alias HashedRangeT!true ConstHashedRange; 3321 alias HashedRangeT!false HashedRange; 3322 3323 template IsMyRange(T) { 3324 enum bool IsMyRange = 3325 is(T == HashedRange) || 3326 is(T == ConstHashedRange) || 3327 is(T == BucketSeqRange) || 3328 is(T == ConstBucketSeqRange); 3329 } 3330 3331 ThisNode*[] hashes; 3332 ThisNode* _first; 3333 double load_factor; 3334 3335 bool isFirst(ThisNode* n){ 3336 version(BucketHackery){ 3337 size_t ix = cast(size_t) n.index!N.prev; 3338 return ix < hashes.length && hashes[ix] == n; 3339 }else{ 3340 return n.index!N.prev is null; 3341 } 3342 } 3343 3344 // sets n as the first in bucket list at index 3345 void setFirst(ThisNode* n, size_t index){ 3346 // first: see if the index of this bucket list is before 3347 // _front's bucket list index 3348 version(BucketHackery){ 3349 size_t findex = !_first?-1: 3350 cast(size_t) _first.index!N.prev; 3351 }else{ 3352 size_t findex = !_first?-1: 3353 hash(key(_first.value))%hashes.length; 3354 } 3355 if(findex >= index) _first = n; 3356 if(hashes[index] && hashes[index] != n){ 3357 version(BucketHackery){ 3358 // be sure not to give insertPrev any bogus 3359 // links to follow and impale itself with 3360 hashes[index].index!N.prev=null; 3361 } 3362 hashes[index].index!N.insertPrev(n); 3363 } 3364 hashes[index] = n; 3365 version(BucketHackery){ 3366 n.index!N.prev = cast(ThisNode*) index; 3367 } 3368 } 3369 3370 void removeFirst(ThisNode* n){ 3371 version(BucketHackery){ 3372 size_t index = cast(size_t) n.index!N.prev; 3373 }else{ 3374 size_t index = hash(key(n.value))%hashes.length; 3375 } 3376 auto nxt = n.index!N.next; 3377 hashes[index] = nxt; 3378 if (nxt){ 3379 version(BucketHackery){ 3380 nxt.index!N.prev = cast(ThisNode*) index; 3381 n.index!N.next = null; 3382 n.index!N.prev = null; 3383 }else{ 3384 nxt.index!N.removePrev(); 3385 } 3386 if(_first == n){ 3387 _first = nxt; 3388 } 3389 }else if(_first == n){ 3390 while(index < hashes.length && !hashes[index]){ 3391 index++; 3392 } 3393 if(index < hashes.length) _first = hashes[index]; 3394 } 3395 } 3396 3397 3398 /** 3399 Returns the number of elements in the container. 3400 3401 Complexity: $(BIGOH 1). 3402 */ 3403 @property size_t length()const{ 3404 return node_count; 3405 } 3406 3407 /** 3408 Property returning $(D true) if and only if the container has no 3409 elements. 3410 3411 Complexity: $(BIGOH 1) 3412 */ 3413 @property bool empty()const{ 3414 return node_count == 0; 3415 } 3416 3417 /** 3418 Preconditions: !empty 3419 Complexity: $(BIGOH 1) 3420 */ 3421 @property front() inout{ 3422 return _first.value; 3423 } 3424 3425 void _ClearIndex(){ 3426 _first = null; 3427 fill(hashes, cast(ThisNode*)null); 3428 } 3429 /** 3430 ?? 3431 */ 3432 void clear(){ 3433 _Clear(); 3434 } 3435 3436 /** 3437 Gets a range of all elements in container. 3438 Complexity: $(BIGOH 1) 3439 */ 3440 HashedRange opSlice(){ 3441 if(empty) return HashedRange(this, null, hashes.length); 3442 auto ix = hash(key(_first.value))%hashes.length; 3443 return HashedRange(this, _first, ix); 3444 } 3445 ConstHashedRange opSlice() const{ 3446 if(empty) 3447 return ConstHashedRange(this, null, hashes.length); 3448 auto ix = hash(key(_first.value))%hashes.length; 3449 return ConstHashedRange(this, _first, ix); 3450 } 3451 3452 // returns true iff k was found. 3453 // when k in hashtable: 3454 // node = first node in hashes[ix] such that eq(key(node.value),k) 3455 // when k not in hashtable: 3456 // node = null -> put value of k in hashes[ix] 3457 // or node is last node in hashes[ix] chain -> 3458 // put value of k in node.next 3459 bool _find(const(KeyType) k, out inout(ThisNode)* node, out size_t index) inout{ 3460 index = hash(k)%hashes.length; 3461 if(!hashes[index]){ 3462 node = null; 3463 return false; 3464 } 3465 node = hashes[index]; 3466 // TODO: figure out unaryFun & inout 3467 while(!eq(k, key(cast()node.value))){ 3468 if (node.index!N.next is null){ 3469 return false; 3470 } 3471 node = node.index!N.next; 3472 } 3473 return true; 3474 } 3475 3476 static if(!allowDuplicates){ 3477 /** 3478 Available for Unique variant. 3479 Complexity: 3480 $(BIGOH n) ($(BIGOH 1) on a good day) 3481 */ 3482 ValueView opIndex ( KeyType k ) const{ 3483 const(ThisNode)* node; 3484 size_t index; 3485 enforce(_find(k, node, index)); 3486 return cast(ValueView) node.value; 3487 } 3488 } 3489 3490 /** 3491 Reports whether a value exists in the collection such that eq(k, key(value)). 3492 Complexity: 3493 $(BIGOH n) ($(BIGOH 1) on a good day) 3494 */ 3495 static if(!isImplicitlyConvertible!(KeyType, ValueView)){ 3496 bool opBinaryRight(string op)(KeyType k) const 3497 if (op == "in") 3498 { 3499 ThisNode* node; 3500 size_t index; 3501 return _find(k, node,index); 3502 } 3503 } 3504 3505 /** 3506 Reports whether value exists in this collection. 3507 Complexity: 3508 $(BIGOH n) ($(BIGOH n 1) on a good day) 3509 */ 3510 bool opBinaryRight(string op)(ValueView value) const 3511 if (op == "in") 3512 { 3513 const(ThisNode)* node; 3514 size_t index; 3515 return _find(key(value), node,index); 3516 } 3517 3518 /** 3519 Reports whether value exists in this collection 3520 Complexity: 3521 $(BIGOH n) ($(BIGOH n 1) on a good day) 3522 */ 3523 bool containsValue(ValueView value) const{ 3524 const(ThisNode)* node; 3525 size_t index; 3526 auto r = _find(key(value), node,index); 3527 return r; 3528 } 3529 3530 ///ditto 3531 bool contains(KeyType k) const{ 3532 const(ThisNode)* node; 3533 size_t index; 3534 return _find(k, node,index); 3535 } 3536 3537 void modify(SomeRange, Modifier)(SomeRange r, Modifier mod) 3538 if(is(SomeRange == HashedRange) || 3539 is(ElementType!SomeRange == Position!ThisNode)) { 3540 while(!r.empty) { 3541 static if(is(SomeRange == HashedRange)) { 3542 ThisNode* node = r.front_node; 3543 }else{ 3544 ThisNode* node = r.front.node; 3545 } 3546 r.popFront(); 3547 _Modify(node, mod); 3548 } 3549 } 3550 3551 bool replace(Position!ThisNode r, ValueView value) { 3552 return _Replace(r.node, cast(Value) value); 3553 } 3554 3555 KeyType _NodePosition(ThisNode* node){ 3556 return key(node.value); 3557 } 3558 3559 // cursor = null -> no fixup necessary or fixup to start of chain 3560 // cursor != null -> fixup necessary 3561 bool _PositionFixable(ThisNode* node, KeyType oldPosition, 3562 out ThisNode* cursor){ 3563 cursor = null; 3564 auto newPosition = key(node.value); 3565 if(eq(newPosition, oldPosition)) return true; 3566 static if(allowDuplicates){ 3567 cursor = node; 3568 return true; 3569 }else{ 3570 ThisNode* n; 3571 size_t index; 3572 return !(_find(newPosition, cursor, index)); 3573 } 3574 3575 } 3576 3577 void _FixPosition(ThisNode* node, KeyType oldPosition, 3578 ThisNode* cursor){ 3579 auto newPosition = key(node.value); 3580 if(eq(newPosition, oldPosition)) return; 3581 static if(allowDuplicates){ 3582 if(cursor){ 3583 _Remove(node); 3584 node.index!N.prev = null; 3585 node.index!N.next = null; 3586 _Insert(node); 3587 } 3588 }else{ 3589 if(eq(oldPosition, key(node.value))) return; 3590 _Remove(node); 3591 _Insert(node, cursor); 3592 } 3593 } 3594 3595 bool _NotifyChange(ThisNode* node){ 3596 size_t index; 3597 if(isFirst(node)){ 3598 version(BucketHackery){ 3599 index = cast(size_t) node.index!N.prev; 3600 }else{ 3601 static assert(0,"signals not implemented for Hashed " ~ 3602 "indices without version=BucketHackery"); 3603 } 3604 }else{ 3605 index = hash(key(node.index!N.prev.value))%hashes.length; 3606 } 3607 3608 size_t newindex = hash(key(node.value))%hashes.length; 3609 if(index != newindex){ 3610 ThisNode* cursor; 3611 _Remove(node); 3612 if(_find(key(node.value), cursor, newindex)){ 3613 static if(!allowDuplicates){ 3614 _RemoveAllBut!N(node); 3615 return false; 3616 }else{ 3617 if(isFirst(cursor)){ 3618 setFirst(node, index); 3619 }else{ 3620 cursor.index!N.insertPrev(node); 3621 } 3622 } 3623 }else if(cursor){ 3624 cursor.index!N.insertNext(node); 3625 }else{ 3626 setFirst(node, index); 3627 } 3628 return true; 3629 } 3630 return true; 3631 } 3632 3633 3634 /** 3635 Returns a range of all elements with eq(key(elem), k). 3636 Complexity: 3637 $(BIGOH n) ($(BIGOH n $(SUB result)) on a good day) 3638 */ 3639 // TODO: compact these back into one 3640 BucketSeqRange equalRange( KeyType k ){ 3641 ThisNode* node; 3642 size_t index; 3643 if(!_find(k, node,index)){ 3644 return BucketSeqRange(this,null,null); 3645 } 3646 static if(!allowDuplicates){ 3647 return BucketSeqRange(this,node,node); 3648 }else{ 3649 ThisNode* node2 = node; 3650 while(node2.index!N.next !is null && 3651 eq(k, key(node2.index!N.next.value))){ 3652 node2 = node2.index!N.next; 3653 } 3654 return BucketSeqRange(this, node, node2); 3655 } 3656 } 3657 ConstBucketSeqRange equalRange( KeyType k ) const{ 3658 const(ThisNode)* node; 3659 size_t index; 3660 if(!_find(k, node,index)){ 3661 return ConstBucketSeqRange(this,null,null); 3662 } 3663 static if(!allowDuplicates){ 3664 return ConstBucketSeqRange(this,node,node); 3665 }else{ 3666 const(ThisNode)* node2 = node; 3667 while(node2.index!N.next !is null && 3668 eq(k, key(node2.index!N.next.value))){ 3669 node2 = node2.index!N.next; 3670 } 3671 return ConstBucketSeqRange(this, node, node2); 3672 } 3673 } 3674 3675 static if(allowDuplicates){ 3676 void _Insert(ThisNode* n){ 3677 ThisNode* cursor; 3678 size_t index; 3679 if(_find(key(n.value), cursor, index)){ 3680 if(isFirst(cursor)){ 3681 setFirst(n, index); 3682 }else{ 3683 cursor.index!N.insertPrev(n); 3684 } 3685 }else if(cursor){ 3686 cursor.index!N.insertNext(n); 3687 }else{ 3688 setFirst(n, index); 3689 } 3690 } 3691 }else{ 3692 bool _DenyInsertion(ThisNode* node, out ThisNode* cursor) 3693 { 3694 size_t index; 3695 auto r = _find(key(node.value), cursor, index); 3696 return r; 3697 } 3698 void _Insert(ThisNode* node, ThisNode* cursor){ 3699 if(cursor){ 3700 cursor.index!N.insertNext(node); 3701 }else{ 3702 size_t index = hash(key(node.value))%hashes.length; 3703 assert ( !hashes[index] ); 3704 setFirst(node, index); 3705 } 3706 } 3707 } 3708 3709 void _Remove(ThisNode* n){ 3710 if(isFirst(n)){ 3711 removeFirst(n); 3712 }else{ 3713 n.index!N.prev.index!N.removeNext(); 3714 } 3715 } 3716 3717 @property loadFactor() const{ 3718 return load_factor; 3719 } 3720 3721 @property loadFactor(size_t _load_factor) { 3722 load_factor = load_factor; 3723 // TODO: what else do we do here? 3724 assert(0); 3725 } 3726 3727 size_t maxLoad(size_t n) const{ 3728 double load = n * load_factor; 3729 if(load > size_t.max) return size_t.max; 3730 return cast(size_t) load; 3731 } 3732 3733 @property size_t capacity() const{ 3734 return hashes.length; 3735 } 3736 3737 void reserve(size_t n){ 3738 if (n <= maxLoad(hashes.length)) return; 3739 size_t i = 0; 3740 while(i < primes.length && maxLoad(primes[i]) < n){ 3741 i++; 3742 } 3743 if (hashes.length == primes[i] && i == primes.length-1){ 3744 // tough 3745 return; 3746 }else if (hashes.length >= primes[i]){ 3747 // hmm. 3748 return; 3749 } 3750 3751 auto r = opSlice(); 3752 auto newhashes = Allocator.allocate!(ThisNode*)(primes[i])[0 .. primes[i]]; 3753 ThisNode* newfirst; 3754 size_t newfindex = -1; 3755 while(!r.empty){ 3756 ThisNode* node = r.front_node; 3757 ThisNode* node2 = node; 3758 auto k = key(node.value); 3759 size_t index = hash(key(node.value))%newhashes.length; 3760 r.popFront(); 3761 while(!r.empty && eq(k, key(r.front))){ 3762 node2 = r.front_node; 3763 r.popFront(); 3764 } 3765 version(BucketHackery){ 3766 node.index!N.prev = cast(ThisNode*)index; 3767 }else{ 3768 node.index!N.prev = null; 3769 } 3770 node2.index!N.next = null; 3771 if(!newhashes[index]){ 3772 newhashes[index] = node; 3773 if (index < newfindex){ 3774 newfirst = node; 3775 newfindex = index; 3776 } 3777 }else{ 3778 auto p = newhashes[index]; 3779 newhashes[index] = node; 3780 node2.index!N.insertNext(p); 3781 if(newfirst == p){ 3782 newfirst = node; 3783 } 3784 } 3785 } 3786 3787 Allocator.deallocate(hashes.ptr); 3788 hashes = newhashes; 3789 _first = newfirst; 3790 } 3791 /** 3792 insert value into this container. For Unique variant, will refuse value 3793 if value already exists in index. 3794 Returns: 3795 number of items inserted into this container. 3796 Complexity: 3797 $(BIGOH i(n)) $(BR) $(BIGOH n) for this index ($(BIGOH 1) on a good day) 3798 */ 3799 size_t insert(SomeValue)(SomeValue value) 3800 if(isImplicitlyConvertible!(SomeValue, ValueView)) { 3801 ThisNode* node; 3802 size_t index; 3803 if(maxLoad(hashes.length) < node_count+1){ 3804 reserve(max(maxLoad(2* hashes.length + 1), node_count+1)); 3805 } 3806 static if(!allowDuplicates){ 3807 // might deny, so have to look 3808 auto k = key(value); 3809 bool found = _find(k, node, index); 3810 if(found) return 0; 3811 ThisNode* newnode = _InsertAllBut!N(value); 3812 if(!newnode) return 0; 3813 }else{ 3814 // won't deny, so don't bother looking until 3815 // we know other indices won't deny. 3816 ThisNode* newnode = _InsertAllBut!N(value); 3817 if(!newnode) return 0; 3818 auto k = key(value); 3819 bool found = _find(k, node, index); 3820 } 3821 if(found){ 3822 // meh, lets not walk to the end of equal range 3823 if (isFirst(node)){ 3824 setFirst(newnode,index); 3825 }else{ 3826 node.index!N.insertPrev(newnode); 3827 } 3828 }else if(node){ 3829 node.index!N.insertNext(newnode); 3830 }else{ 3831 setFirst(newnode,index); 3832 } 3833 return 1; 3834 } 3835 3836 /** 3837 insert contents of r into this container. For Unique variant, will refuse 3838 any items in content if it already exists in index. 3839 Returns: 3840 number of items inserted into this container. 3841 Complexity: 3842 $(BIGOH i(n)) $(BR) $(BIGOH n+n $(SUB r)) for this index 3843 ($(BIGOH n $(SUB r)) on a good day) 3844 */ 3845 size_t insert(SomeRange)(SomeRange r) 3846 if(isImplicitlyConvertible!(ElementType!SomeRange, ValueView)){ 3847 size_t count = 0; 3848 static if(hasLength!SomeRange){ 3849 if(maxLoad(node_count) < node_count+r.length){ 3850 reserve(max(2 * node_count + 1, node_count+r.length)); 3851 } 3852 } 3853 foreach(e; r){ 3854 count += insert(e); 3855 static if(hasLength!SomeRange){ 3856 if(maxLoad(node_count) < node_count+1){ 3857 reserve(max(2* node_count + 1, node_count+1)); 3858 } 3859 } 3860 } 3861 return count; 3862 } 3863 3864 /** 3865 Removes all of r from this container. 3866 Preconditions: 3867 r came from this index 3868 Returns: 3869 an empty range 3870 Complexity: 3871 $(BIGOH n $(SUB r) * d(n)), $(BR) 3872 $(BIGOH n $(SUB r)) for this index 3873 */ 3874 HashedRange remove(R)( R r ) 3875 if(is(R == HashedRange) || is(R == BucketSeqRange) || 3876 is(ElementType!R == Position!ThisNode)){ 3877 while(!r.empty){ 3878 static if(IsMyRange!R){ 3879 ThisNode* node = r.front_node; 3880 }else{ 3881 ThisNode* node = r.front.node; 3882 r.front.obliterated = true; 3883 } 3884 r.popFront(); 3885 _RemoveAll(node); 3886 } 3887 return HashedRange(this, null, hashes.length); 3888 } 3889 3890 /** 3891 Removes all elements with key k from this container. 3892 Returns: 3893 the number of elements removed 3894 Complexity: 3895 $(BIGOH n $(SUB k) * d(n)), $(BR) 3896 $(BIGOH n + n $(SUB k)) for this index ($(BIGOH n $(SUB k)) on a good day) 3897 */ 3898 version(OldWay){ 3899 size_t removeKey(KeyType k){ 3900 auto r = equalRange(k); 3901 size_t count = 0; 3902 while(!r.empty){ 3903 ThisNode* node = r._front; 3904 r.popFront(); 3905 _RemoveAll(node); 3906 count++; 3907 } 3908 return count; 3909 } 3910 }else{ 3911 3912 size_t removeKey(Keys...)(Keys keys) 3913 if(allSatisfy!(implicitlyConverts,Keys)) { 3914 Unqual!KeyType[Keys.length] toRemove; 3915 foreach(i,k; keys) { 3916 Unqual!KeyType k2 = k; 3917 toRemove[i] = k2; 3918 } 3919 return removeKey(cast(KeyType[]) (toRemove[])); 3920 } 3921 3922 size_t removeKey(Key)(Key[] keys) 3923 if(isImplicitlyConvertible!(Key, KeyType)) 3924 out(r){ 3925 version(RBDoChecks) _Check(); 3926 }body{ 3927 ThisNode* node; 3928 size_t index; 3929 size_t count = 0; 3930 3931 foreach(k; keys) 3932 { 3933 if(!_find(k, node, index)){ 3934 continue; 3935 } 3936 _RemoveAll(node); 3937 count++; 3938 } 3939 3940 return count; 3941 } 3942 3943 private template implicitlyConverts(Key){ 3944 enum implicitlyConverts = isImplicitlyConvertible!(Key,KeyType); 3945 } 3946 3947 /++ Ditto +/ 3948 size_t removeKey(Stuff)(Stuff stuff) 3949 if(isInputRange!Stuff && 3950 isImplicitlyConvertible!(ElementType!Stuff, KeyType) && 3951 !isDynamicArray!Stuff) { 3952 //We use array in case stuff is a Range from this 3953 // hash - either directly or indirectly. 3954 auto stuffy = allocatedArray!Allocator(stuff); 3955 auto res = removeKey(stuffy); 3956 Allocator.deallocate(stuffy.ptr); 3957 return res; 3958 } 3959 } 3960 3961 void _NodeReplace(ThisNode* old, ThisNode* newnode) { 3962 ThisNode* next = old.index!N.next; 3963 ThisNode* prev = old.index!N.prev; 3964 newnode.index!N.next = next; 3965 newnode.index!N.prev = prev; 3966 if(next) { 3967 next.index!N.prev = newnode; 3968 } 3969 if(prev) { 3970 prev.index!N.next = newnode; 3971 } 3972 if(old is _first) { 3973 _first = newnode; 3974 } 3975 3976 old.index!N.prev = null; 3977 old.index!N.next = null; 3978 } 3979 3980 void _Check(){ 3981 bool first = true; 3982 foreach(i, node; hashes){ 3983 if(!node) continue; 3984 if(first){ 3985 assert(_first is node); 3986 first = false; 3987 } 3988 assert(isFirst(node)); 3989 ThisNode* prev = null; 3990 while(node){ 3991 3992 assert(hash(key(node.value))%hashes.length == i); 3993 if(!isFirst(node)){ 3994 static if(!allowDuplicates){ 3995 assert(!eq(key(prev.value), key(node.value))); 3996 } 3997 // gonna be hard to enforce that equal elements are contiguous 3998 } 3999 4000 prev = node; 4001 node = node.index!N.next; 4002 } 4003 } 4004 } 4005 4006 string toString0(){ 4007 string r = "["; 4008 auto rng = opSlice(); 4009 while(!rng.empty){ 4010 r ~= format("%s", (rng.front)); 4011 rng.popFront(); 4012 r ~= rng.empty ? "]" : ", "; 4013 } 4014 return r; 4015 } 4016 4017 private HashedRange fromNode(ThisNode* n){ 4018 auto ix = hash(key(n.value))%this.index!N.hashes.length; 4019 return HashedRange(this, n, ix); 4020 } 4021 } 4022 } 4023 } 4024 4025 /// _ 4026 template HashedUnique(alias KeyFromValue="a", 4027 alias Hash="typeid(a).getHash(&a)", alias Eq="a==b"){ 4028 alias Hashed!(false, KeyFromValue, Hash, Eq) HashedUnique; 4029 } 4030 /// _ 4031 template HashedNonUnique(alias KeyFromValue="a", 4032 alias Hash="typeid(a).getHash(&a)", alias Eq="a==b"){ 4033 alias Hashed!(true, KeyFromValue, Hash, Eq) HashedNonUnique; 4034 } 4035 4036 4037 class Position(MNode) { 4038 alias MNode.ThisContainer.ValueView ValueView; 4039 alias MNode.ThisContainer.Allocator Allocator; 4040 4041 new(size_t sz) { 4042 void* p = Allocator.allocate!void(sz); 4043 return p; 4044 } 4045 delete(void* p) { 4046 Allocator.deallocate(p); 4047 } 4048 4049 @property ValueView v() { 4050 return node.value; 4051 } 4052 4053 private: 4054 bool obliterated = true; 4055 MNode* _node; 4056 4057 this(MNode* _node) { 4058 obliterated = false; 4059 this._node = _node; 4060 } 4061 4062 @property node() { 4063 enforce(!obliterated, 4064 "this position no longer exists in container"); 4065 return _node; 4066 } 4067 } 4068 4069 auto PSR(Range)(Range rng) 4070 { 4071 alias Position!(typeof(*rng.front_node)) Pos; 4072 4073 static struct PositionRange { 4074 4075 Range source; 4076 4077 @property empty() { 4078 return source.empty(); 4079 } 4080 4081 @property Pos front() { 4082 return new Pos(source.front_node); 4083 } 4084 4085 void popFront() { 4086 source.popFront(); 4087 } 4088 4089 static if(isBidirectionalRange!Range) { 4090 @property Pos back() { 4091 return new Pos(source.back_node); 4092 } 4093 4094 void popBack() { 4095 source.popBack(); 4096 } 4097 } 4098 4099 static if(isForwardRange!Range) { 4100 @property save() { 4101 return PositionRange(source.save()); 4102 } 4103 } 4104 4105 static if(isRandomAccessRange!Range) { 4106 auto opIndex(size_t i) { 4107 return source.nth_node(i); 4108 } 4109 4110 @property length() { 4111 return source.length; 4112 } 4113 4114 @property front(typeof(source.front_node) n) { 4115 source.front_node = n; 4116 } 4117 4118 @property opSlice(size_t a, size_t b) { 4119 return PositionRange(source[a .. b]); 4120 } 4121 } 4122 } 4123 4124 return PositionRange(rng); 4125 } 4126 4127 struct IndexedBy(L...) 4128 { 4129 template _inner(size_t index, List...) { 4130 static if(List.length <= 1) { 4131 alias TypeTuple!() names; 4132 alias TypeTuple!() name_indices; 4133 alias TypeTuple!(List) indices; 4134 }else static if(IsIndex!(List[0]) && is(typeof(List[1]) == string)) { 4135 alias _inner!(index+1,List[2 .. $]) next; 4136 alias TypeTuple!(List[1], next.names) names; 4137 alias TypeTuple!(index, next.name_indices) name_indices; 4138 alias TypeTuple!(List[0], next.indices) indices; 4139 }else { 4140 alias _inner!(index+1,List[1 .. $]) next; 4141 alias next.names names; 4142 alias next.name_indices name_indices; 4143 alias TypeTuple!(List[0], next.indices) indices; 4144 } 4145 } 4146 4147 alias _inner!(0, L).names Names; 4148 alias _inner!(0, L).name_indices NameIndices; 4149 alias _inner!(0, L).indices Indices; 4150 alias L List; 4151 } 4152 4153 template GetMixinAlias(valueSignal){ 4154 alias valueSignal.MixinAlias GetMixinAlias; 4155 } 4156 4157 // todo - find better name 4158 template OU(T){ 4159 template arr2tuple(stuff...){ 4160 static assert(is(typeof(stuff[0]) == T[])); 4161 4162 static if(stuff[0].length){ 4163 alias arr2tuple!(stuff[0][1 .. $], stuff[1 .. $], stuff[0][0]) arr2tuple; 4164 }else{ 4165 alias stuff[1 .. $] arr2tuple; 4166 } 4167 } 4168 4169 T[] orderedUniqueInsert(T[] x, T value){ 4170 size_t i; 4171 while(i < x.length && x[i] < value) i++; 4172 if(i < x.length && x[i] == value) return x; 4173 T[] ret = new T[](x.length+1); 4174 ret[0 .. i] = x[0 .. i]; 4175 ret[i] = value; 4176 ret[i+1 .. $] = x[i .. $]; 4177 return ret; 4178 } 4179 T[] TypeList2SortedArray(L...)(){ 4180 alias L List; 4181 T[] ret = []; 4182 foreach(T l; List){ 4183 ret = orderedUniqueInsert(ret, l); 4184 } 4185 return ret; 4186 } 4187 } 4188 4189 /** 4190 Specifies how to hook up value signals to indices. 4191 4192 A value type Value is a signal whenever Value supports the signal 4193 interface, ie $(BR) 4194 4195 value.connect(void delegate() slot) $(BR) 4196 value.disconnect(void delegate() slot) 4197 4198 and has the semantics that whenever value changes in a way that will cause 4199 its position in index to change or become invalid, a call is made to slot. 4200 The index will respond by fixing the position, or if that is not possible, 4201 by throwing an exception. 4202 4203 A value may contain multiple signals within different mixin aliases. If this 4204 is the case, the interface is 4205 4206 value.mixinAlias.connect(void delegate() slot) $(BR) 4207 value.mixinAlias.disconnect(void delegate() slot) 4208 4209 where mixinAlias is passed in as a string to each element of L. 4210 4211 Arguments must be instantiations of ValueSignal. 4212 4213 Signals to single indices can be specified by ValueSignal!(index[, mixinAlias]) 4214 4215 Signals to all indices can be specified by ValueSignal!("*"[, mixinAlias]) 4216 4217 A signal can be shared by multiple indices; however do not associate a signal 4218 to the same index more than once. 4219 */ 4220 4221 struct ValueChangedSlots(L...) { 4222 struct Inner(IndexedBy){ 4223 // by some forward referencing error or other, (issue 6475) 4224 // I can't seem to get a hold of inner in, but 4225 // typeof(exposeType()) seems to work. Desparate times require 4226 // desparate measures, I guess 4227 static exposeType(){ 4228 Inner i; 4229 return i; 4230 } 4231 enum N = IndexedBy.Indices.length; 4232 alias ExpandStarSignals!(IndexedBy,L) List; 4233 4234 4235 template GetIndex(valueSignal){ 4236 static if(__traits(compiles,valueSignal.Index)){ 4237 enum GetIndex = valueSignal.Index; 4238 }else{ 4239 static assert(__traits(compiles,valueSignal.Tag)); 4240 static if(valueSignal.Tag == "*") { 4241 static assert(false, "you bad, bad person"); 4242 }else { 4243 enum _TagIndex = staticIndexOf!(valueSignal.Tag, IndexedBy.Names); 4244 enum GetIndex = IndexedBy.NameIndices[_TagIndex]; 4245 } 4246 } 4247 } 4248 4249 enum string[] AllSignals = OU!(string).TypeList2SortedArray!( 4250 NoDuplicates!(staticMap!(GetMixinAlias, List)))(); 4251 4252 template FindIndices(string mixinAlias, size_t i, indices...) 4253 if(indices.length == 1 && is(typeof(indices[0]) == size_t[])){ 4254 static if(i < List.length){ 4255 static if(List[i].MixinAlias == mixinAlias){ 4256 enum index = GetIndex!(List[i]); 4257 static if(IndexedBy.Indices[index].BenefitsFromSignals){ 4258 enum size_t[] result = 4259 FindIndices!(mixinAlias, i+1, 4260 OU!(size_t).orderedUniqueInsert( 4261 indices[0], index)).result; 4262 }else{ 4263 enum size_t[] result = 4264 FindIndices!(mixinAlias, i+1, indices[0]).result; 4265 } 4266 }else{ 4267 enum size_t[] result = 4268 FindIndices!(mixinAlias, i+1, indices[0]).result; 4269 } 4270 }else{ 4271 enum size_t[] result = indices[0]; 4272 } 4273 } 4274 4275 template GenSets(size_t i, MI...){ 4276 static if (i < AllSignals.length){ 4277 enum mixinAlias = AllSignals[i]; 4278 enum indices = FindIndices!(mixinAlias,0,cast(size_t[])[]).result; 4279 template InsertIndices(size_t j){ 4280 static if(j < MI.length){ 4281 static if(MI[j].Indices == indices){ 4282 alias TypeTuple!(MI[0 .. j], 4283 Mixin2Indices!( 4284 OU!(string).orderedUniqueInsert( 4285 MI[j].MixinAliases,mixinAlias), 4286 indices 4287 ), 4288 MI[j+1 .. $]) InsertIndices; 4289 }else{ 4290 alias InsertIndices!(i+1) InsertIndices; 4291 } 4292 }else{ 4293 alias TypeTuple!(MI, Mixin2Indices!([mixinAlias], 4294 indices)) InsertIndices; 4295 } 4296 } 4297 4298 static if(indices.length > 0){ 4299 alias InsertIndices!(0) MI2; 4300 alias GenSets!(i+1, MI2).result result; 4301 }else{ 4302 alias GenSets!(i+1, MI).result result; 4303 } 4304 }else{ 4305 alias MI result; 4306 } 4307 } 4308 4309 // map { set of mixin aliases -> set of indices } 4310 // since we don't have maps or sets in ct (boo), 4311 // really this is a list of ((list of mixin aliases), (list of indices)) 4312 // with each inner list sorted ascending. 4313 // 4314 // what's the background? 4315 // we want to generate no more than M slots for this index/signal 4316 // spec, where M is the number of distinct signals (mixin aliases) 4317 // passed in. This should minimize the amount of additional memory 4318 // that each value has to keep track of. 4319 // 4320 // We also want to know when different signals share the same index 4321 // set, so we don't have to generate redundant slots. 4322 // so we generate this mapping, which should help. 4323 // 4324 // Requires: In the map's key set - a set of sets of mixin aliases - 4325 // each mixin appears in exactly one set. (it is a true set) 4326 // The map's value set - a set of sets of indices - is a true set, 4327 // each index set is unique 4328 // 4329 // Then: for each entry in the map (K,V), we generate a slot function W 4330 // inside our node. W gets connected/disconnected to/from each of 4331 // the signals in K. W notifies each of the indices in V. 4332 4333 alias GenSets!(0).result Mixin2Index; 4334 4335 4336 template _GetIndicesForSignal(string signal, size_t i){ 4337 static if(i < N){ 4338 static if(staticIndexOf!(signal, GetMixinAliases!(List[i])) 4339 != -1){ 4340 alias TypeTuple!(i,_GetIndicesForSignal!(signal,i+1)) 4341 _GetIndicesForSignal; 4342 }else{ 4343 alias _GetIndicesForSignal!(signal,i+1) 4344 _GetIndicesForSignal; 4345 } 4346 }else{ 4347 alias TypeTuple!() _GetIndicesForSignal; 4348 } 4349 } 4350 4351 template GetIndicesForSignal(string signal){ 4352 alias _GetIndicesForSignal!(signal, 0) GetIndicesForSignal; 4353 } 4354 } 4355 } 4356 4357 template ExpandStarSignals(IndexedBy, L...) { 4358 static if(L.length == 0) { 4359 alias TypeTuple!() ExpandStarSignals; 4360 }else static if(__traits(compiles,L[0].Tag) && L[0].Tag == "*") { 4361 alias TypeTuple!(ExpandStarSignal!(IndexedBy, 0, L[0]), 4362 ExpandStarSignals!(IndexedBy, L[1 .. $])) ExpandStarSignals; 4363 }else{ 4364 alias TypeTuple!(L[0], ExpandStarSignals!(IndexedBy, L[1 .. $])) 4365 ExpandStarSignals; 4366 } 4367 } 4368 4369 template ExpandStarSignal(IndexedBy, size_t i, ProtoSignal) { 4370 static if(i >= IndexedBy.Indices.length) { 4371 alias TypeTuple!() ExpandStarSignal; 4372 }else { 4373 alias TypeTuple!(ValueSignal!(i, ProtoSignal.MixinAlias), 4374 ExpandStarSignal!(IndexedBy, i+1, ProtoSignal)) ExpandStarSignal; 4375 } 4376 4377 } 4378 4379 /// _ 4380 struct ValueSignal(size_t index, string mixinAlias = "") 4381 { 4382 enum size_t Index = index; 4383 enum MixinAlias = mixinAlias; 4384 } 4385 4386 /// _ 4387 struct ValueSignal(string tag, string mixinAlias = "") 4388 { 4389 enum Tag = tag; 4390 enum MixinAlias = mixinAlias; 4391 } 4392 4393 struct Mixin2Indices(stuff...) 4394 // wish we could pass arrays directly (cough) 4395 if(stuff.length == 2 && is(typeof(stuff[0]) == string[]) && 4396 is(typeof(stuff[1]) == size_t[])){ 4397 enum string[] MixinAliases = stuff[0]; 4398 enum size_t[] Indices = stuff[1]; 4399 } 4400 4401 4402 /++ 4403 A multi_index node. Holds the value of a single element, 4404 plus per-node headers of each index, if any. 4405 The headers are all mixed in in the same scope. To prevent 4406 naming conflicts, a header field must be accessed with the number 4407 of its index. 4408 Example: 4409 ---- 4410 alias MNode!(IndexedBy!(Sequenced!(), Sequenced!(), OrderedUnique!()), int) Node; 4411 Node* n1 = new Node(); 4412 Node* n2 = new Node(); 4413 n1.index!0 .next = n2; 4414 n2.index!0 .prev = n1; 4415 n1.index!1 .prev = n2; 4416 n2.index!1 .next = n1; 4417 n1.index!2 .left = n2; 4418 ---- 4419 +/ 4420 struct MNode(_ThisContainer, IndexedBy, Allocator, Signals, Value, ValueView) { 4421 alias _ThisContainer ThisContainer; 4422 static if(MutableValue!(MNode, Value)) { 4423 Value value; 4424 }else{ 4425 // do a dumb tail const sort of thing 4426 struct Capsule { 4427 Value value; 4428 } 4429 Capsule* val_ptr; 4430 4431 @property Value value() pure inout { return val_ptr.value; } 4432 @property void value(Value v) { 4433 if(val_ptr != null) { 4434 Allocator.deallocate(val_ptr); 4435 } 4436 val_ptr = Allocator.allocate!(Capsule)(1); 4437 Capsule c = Capsule(v); 4438 move(c, *val_ptr); 4439 } 4440 this(Value val) { 4441 this.value = val; 4442 } 4443 ~this() { 4444 if(val_ptr != null) { 4445 Allocator.deallocate(val_ptr); 4446 val_ptr = null; 4447 } 4448 } 4449 } 4450 4451 static if(Signals.AllSignals.length > 0) { 4452 // notifications need to go somewhere 4453 ThisContainer container; 4454 4455 /// generate slots 4456 template ForEachSignal(size_t i) { 4457 static if(i < Signals.Mixin2Index.length) { 4458 alias Signals.Mixin2Index[i] Mixin2Index; 4459 4460 template ForEachIndex2(size_t j) { 4461 static if(j < Mixin2Index.Indices.length) { 4462 enum result = Replace!(q{ 4463 if(!container.index!($i)._NotifyChange(&this)) { 4464 goto denied; 4465 } 4466 }, "$i", Mixin2Index.Indices[j]) ~ ForEachIndex2!(j+1).result; 4467 }else{ 4468 enum result = ""; 4469 } 4470 } 4471 enum stuff = Replace!(q{ 4472 void slot$i(){ 4473 $x 4474 return; 4475 denied: enforce(false, "todo: put a useful message in here"); 4476 } 4477 }, "$i", i, "$x", ForEachIndex2!(0).result); 4478 }else{ 4479 enum stuff = ""; 4480 } 4481 } 4482 4483 enum signal_stuff = ForEachSignal!(0).stuff; 4484 mixin(signal_stuff); 4485 } 4486 4487 4488 template ForEachIndex(size_t N,L...){ 4489 static if(L.length > 0){ 4490 enum indexN = Replace!("index%s","%s", N); 4491 //alias L[0] L0; 4492 enum result = 4493 Replace!(q{ 4494 alias IndexedBy.Indices[$N] L$N; 4495 alias L$N.Inner!(ThisContainer, typeof(this),Value,ValueView,$N, Allocator) M$N; 4496 mixin M$N.NodeMixin!(M$N.NodeTuple) index$N; 4497 template index(size_t n) if(n == $N){ alias index$N index; } 4498 }, "$N", N) ~ 4499 ForEachIndex!(N+1, L[1 .. $]).result; 4500 }else{ 4501 enum result = ""; 4502 } 4503 } 4504 4505 enum stuff = ForEachIndex!(0, IndexedBy.Indices).result; 4506 mixin(stuff); 4507 } 4508 4509 struct ConstView{} 4510 struct MutableView{} 4511 4512 template IsIndexedBy(alias x) { 4513 // test x.stringof in case we have a bare Sequenced!() or somesuch 4514 enum bool IsIndexedBy = __traits(compiles, x.stringof) && 4515 x.stringof.startsWith("IndexedBy!") && 4516 __traits(compiles, x.List); 4517 } 4518 4519 template IsIndex(alias x) { 4520 enum bool IsIndex = __traits(hasMember, x, "Inner"); 4521 } 4522 4523 int IndexedByCount(X...)() { 4524 int r = 0; 4525 foreach(i,x; X){ 4526 static if(__traits(compiles,IsIndexedBy!x) && IsIndexedBy!x) { 4527 r++; 4528 } 4529 } 4530 return r; 4531 } 4532 size_t[] IndexedByAllIndices(X)() { 4533 // erm. returns list of nonindices in IndexedBy 4534 size_t[] res = []; 4535 foreach(i,x; X.List){ 4536 static if(!IsIndex!x && 4537 (i == 0 || !IsIndex!(X.List[i-1]) || !is(typeof(x) == string))) { 4538 res ~= i; 4539 } 4540 } 4541 return res; 4542 } 4543 4544 4545 template FindIndexedBy(Args...) { 4546 static if(IsIndexedBy!(Args[0])) { 4547 alias Args[0] FindIndexedBy; 4548 }else { 4549 alias FindIndexedBy!(Args[1 .. $]) FindIndexedBy; 4550 } 4551 } 4552 4553 template IsValueChangedSlots(alias X) { 4554 enum bool IsValueChangedSlots = __traits(compiles, X.stringof) && 4555 X.stringof.startsWith("ValueChangedSlots!"); 4556 } 4557 4558 int ValueChangedSlotsCount(Args...)() { 4559 int r = 0; 4560 foreach(i,x; Args){ 4561 static if(__traits(compiles,IsValueChangedSlots!x) && IsValueChangedSlots!x) { 4562 r++; 4563 } 4564 } 4565 return r; 4566 } 4567 4568 template FindValueChangedSlots(Args...) { 4569 static if(Args.length == 0) { 4570 alias ValueChangedSlots!() FindValueChangedSlots; 4571 }else static if(IsValueChangedSlots!(Args[0])) { 4572 alias Args[0] FindValueChangedSlots; 4573 }else { 4574 alias FindValueChangedSlots!(Args[1 .. $]) FindValueChangedSlots; 4575 } 4576 } 4577 4578 template IsConstnessView(alias T) { 4579 enum bool IsConstnessView = is(T == MutableView) || is(T == ConstView); 4580 } 4581 4582 int ConstnessViewCount(Args...)() { 4583 int r = 0; 4584 foreach(i,x; Args){ 4585 static if(__traits(compiles,IsConstnessView!x) && IsConstnessView!x) { 4586 r++; 4587 } 4588 } 4589 return r; 4590 } 4591 4592 template FindConstnessView(Args...) { 4593 static if(Args.length == 0) { 4594 alias ConstView FindConstnessView; 4595 }else static if(IsConstnessView!(Args[0])) { 4596 alias Args[0] FindConstnessView; 4597 }else { 4598 alias FindConstnessView!(Args[1 .. $]) FindConstnessView; 4599 } 4600 } 4601 4602 int AllocatorCount(Args...)() { 4603 int r = 0; 4604 foreach(i,x; Args){ 4605 static if(__traits(compiles, IsAllocator!x) && IsAllocator!x) { 4606 r++; 4607 } 4608 } 4609 return r; 4610 } 4611 4612 template FindAllocator(Args...) { 4613 static if(Args.length == 0) { 4614 alias GCAllocator FindAllocator; 4615 }else static if(IsAllocator!(Args[0])) { 4616 alias Args[0] FindAllocator; 4617 }else { 4618 alias FindAllocator!(Args[1 .. $]) FindAllocator; 4619 } 4620 } 4621 4622 size_t[] IndexGarbage(Args...)() { 4623 size_t[] res = []; 4624 foreach(i,x; Args){ 4625 static if(!(__traits(compiles,IsIndexedBy!x) && IsIndexedBy!x) && 4626 !(__traits(compiles,IsValueChangedSlots!x) && IsValueChangedSlots!x) && 4627 !(__traits(compiles,IsConstnessView!x) && IsConstnessView!x) && 4628 !(__traits(compiles,IsAllocator!x) && IsAllocator!x)) { 4629 res ~= i; 4630 } 4631 } 4632 return res; 4633 } 4634 4635 4636 struct ComparisonEx(alias _key, alias _less) { 4637 alias _less _less_; 4638 alias binaryFun!_less less; 4639 alias unaryFun!_key key; 4640 } 4641 4642 struct DefaultComparison(alias _less) { 4643 alias _less less; 4644 } 4645 4646 template MultiCompare(F...) { 4647 template NormComps(size_t i = 0, alias Dflt = "a<b") { 4648 static if(i == F.length) { 4649 alias TypeTuple!() NormComps; 4650 }else { 4651 static if(F[i].stringof.startsWith("DefaultComparison!") && 4652 __traits(compiles, F[i].less)) { 4653 alias NormComps!(i+1, F[i].less) NormComps; 4654 }else{ 4655 static if (F[i].stringof.startsWith("ComparisonEx!") && 4656 __traits(compiles, F[i].less) && 4657 __traits(compiles, F[i].key)) { 4658 alias F[i] Cmp; 4659 }else { 4660 alias ComparisonEx!(F[i], Dflt) Cmp; 4661 } 4662 alias TypeTuple!(Cmp, NormComps!(i+1, Dflt)) NormComps; 4663 } 4664 } 4665 } 4666 4667 alias NormComps!() Comps; 4668 4669 bool MultiCompare(T)(T a, T b) { 4670 foreach(i, cmp; Comps) { 4671 auto a1 = cmp.key(a); 4672 auto b1 = cmp.key(b); 4673 auto less = cmp.less(a1,b1); 4674 if(less) return true; 4675 auto gtr = cmp.less(b1,a1); 4676 if(gtr) return false; 4677 static if(i == Comps.length-1) { 4678 return false; 4679 } 4680 } 4681 assert(0); 4682 } 4683 } 4684 4685 template IsCompatibleLess(Less, Key, CKey) { 4686 enum bool IsCompatibleLess = is(typeof({ 4687 Less less; 4688 auto c = CKey.init; 4689 auto k = Key.init; 4690 less.cc_less(c,c); 4691 less.kc_less(k,c); 4692 less.ck_less(c,k); 4693 })); 4694 } 4695 4696 struct CriterionFromKey(MultiIndex, size_t index, 4697 alias CompatibleKeyFromKey, 4698 alias CompatibleLess = "a<b") { 4699 alias binaryFun!CompatibleLess less; 4700 alias MultiIndex.index!(index).key key; 4701 alias MultiIndex.index!(index).KeyType KeyType; 4702 alias unaryFun!CompatibleKeyFromKey ckey; 4703 alias typeof(ckey(MultiIndex.ValueView.init)) CompatibleKeyType; 4704 4705 static: 4706 bool kc_less(KeyType a, CompatibleKeyType b) { 4707 return less(ckey(a),b); 4708 } 4709 bool ck_less(CompatibleKeyType a, KeyType b) { 4710 return less(a, ckey(b)); 4711 } 4712 bool cc_less(CompatibleKeyType a, CompatibleKeyType b) { 4713 return less(a, b); 4714 } 4715 } 4716 4717 // error sinks 4718 4719 class MultiIndexContainer(Value, Args...) 4720 if(IndexedByCount!(Args)() != 1) { 4721 static assert (IndexedByCount!(Args)() > 0, "MultiIndexContainer requires indices to be wrapped with IndexedBy!(..)"); 4722 static assert (IndexedByCount!(Args)() < 2, "MultiIndexContainer takes exactly one IndexedBy!(..)"); 4723 } 4724 4725 class MultiIndexContainer(Value, Args...) 4726 if(FindIndexedBy!Args .List.length == 0) { 4727 static assert(false, "MultiIndexContainer requires at least one index"); 4728 } 4729 4730 class MultiIndexContainer(Value, Args...) 4731 if(IndexedByAllIndices!(FindIndexedBy!Args)().length != 0) { 4732 import std.conv; 4733 alias FindIndexedBy!Args IndexedBy; 4734 enum lst = IndexedByAllIndices!(IndexedBy)(); 4735 pragma(msg, "IndexedBy contains non-index at indices"); 4736 mixin template Frch(size_t i) { 4737 static if(i < lst.length) { 4738 static if(__traits(compiles, IndexedBy.List[lst[i]].stringof)) { 4739 pragma(msg, to!string(lst[i]) ~ ": " ~ IndexedBy.List[lst[i]].stringof); 4740 }else{ 4741 pragma(msg, to!string(lst[i])); 4742 } 4743 mixin Frch!(i+1); 4744 } 4745 } 4746 mixin Frch!(0); 4747 static assert(false); 4748 // @@@ PHOBOS ISSUE 8320 @@@ 4749 /+ 4750 static assert (false, 4751 Replace!(/*"IndexedBy contains non-index at indices*/" %s", "%s", 4752 IndexedByAllIndices!(FindIndexedBy!Args)())); 4753 +/ 4754 } 4755 4756 class MultiIndexContainer(Value, Args...) 4757 if(ValueChangedSlotsCount!(Args)() > 1) { 4758 static assert(false, "Multiple ValueChangedSlots specifications are not allowed"); 4759 } 4760 4761 class MultiIndexContainer(Value, Args...) 4762 if(ConstnessViewCount!(Args)() > 1) { 4763 static assert(false, "Multiple Constness Views are not allowed"); 4764 } 4765 4766 class MultiIndexContainer(Value, Args...) 4767 if(AllocatorCount!(Args)() > 1) { 4768 static assert(false, "Multiple allocators are not allowed"); 4769 } 4770 4771 class MultiIndexContainer(Value, Args...) 4772 if(IndexGarbage!(Args)().length != 0) { 4773 import std.conv; 4774 enum lst = IndexGarbage!(Args)(); 4775 pragma(msg, "MultiIndexContainer unknown arguments at"); 4776 mixin template Frch(size_t i) { 4777 static if(i < lst.length) { 4778 static if(__traits(compiles, Args[lst[i]].stringof)) { 4779 pragma(msg, to!string(lst[i]) ~ ": " ~ Args[lst[i]].stringof); 4780 }else{ 4781 pragma(msg, to!string(lst[i])); 4782 } 4783 mixin Frch!(i+1); 4784 } 4785 } 4786 mixin Frch!(0); 4787 static assert(false); 4788 // @@@ PHOBOS ISSUE 8320 @@@ 4789 /+ 4790 static assert (false, 4791 Replace!(/*"IndexedBy contains non-index at indices*/" %s", "%s", 4792 IndexedByAllIndices!(FindIndexedBy!Args)())); 4793 +/ 4794 } 4795 4796 template MutableValue(Node, Value) { 4797 enum MutableValue = __traits(compiles, { Value value; value = Value.init; }); 4798 } 4799 4800 template _AllUnique(Thing...) { 4801 enum _AllUnique = NoDuplicates!Thing .length == Thing.length; 4802 } 4803 class MultiIndexContainer(Value, Args...) 4804 if(!_AllUnique!(FindIndexedBy!Args .Names)) { 4805 static assert(false, "duplicates!"); 4806 } 4807 4808 4809 4810 // end error sinks 4811 4812 /++ 4813 The container. Don't call any index methods from this container directly; use 4814 a reference to an individual index, which can be obtained via 4815 --- 4816 container.get_index!N 4817 --- 4818 or 4819 --- 4820 container.name 4821 --- 4822 for named indices. 4823 4824 If you have a range into an index of this container, you can convert it to a 4825 range of index N via 4826 --- 4827 container.to_range!N(range) 4828 --- 4829 This is equivalent to c++ multi_index' project 4830 +/ 4831 class MultiIndexContainer(Value, Args...) 4832 if(IndexedByCount!(Args)() == 1 && 4833 FindIndexedBy!Args .List.length != 0 && 4834 IndexedByAllIndices!(FindIndexedBy!Args)().length == 0 && 4835 _AllUnique!(FindIndexedBy!Args .Names) && 4836 ValueChangedSlotsCount!(Args)() <= 1 && 4837 ConstnessViewCount!(Args)() <= 1 && 4838 AllocatorCount!(Args)() <= 1 && 4839 IndexGarbage!(Args)().length == 0) { 4840 4841 alias FindIndexedBy!Args IndexedBy; 4842 // @@@ DMD ISSUE 6475 @@@ following gives forward reference error 4843 //alias FindValueChangedSlots!Args .Inner!(IndexedBy) NormSignals; 4844 alias typeof(FindValueChangedSlots!Args .Inner!(IndexedBy).exposeType()) NormSignals; 4845 alias FindConstnessView!Args ConstnessView; 4846 alias FindAllocator!Args Allocator; 4847 4848 static if(is(ConstnessView == ConstView)){ 4849 alias const(Value) ValueView; 4850 }else static if(is(ConstnessView == MutableView)){ 4851 alias Value ValueView; 4852 }else static assert(false); 4853 alias MNode!(typeof(this), IndexedBy,Allocator,NormSignals,Value, ValueView) ThisNode; 4854 4855 /+ 4856 template IndexedByList0(size_t i, stuff...){ 4857 static if(i < IndexedBy.Indices.length){ 4858 alias typeof(IndexedBy.Indices[i].Inner!(typeof(this), ThisNode, Value, i).exposeType()) x; 4859 alias IndexedByList0!(i+1, stuff, x).result result; 4860 }else{ 4861 alias stuff result; 4862 } 4863 } 4864 4865 alias IndexedByList0!(0).result IndexedByList; 4866 +/ 4867 4868 size_t node_count; 4869 4870 template ForEachCtorMixin(size_t i){ 4871 static if(i < IndexedBy.Indices.length){ 4872 static if(is(typeof(IndexedBy.Indices[i].Inner!(typeof(this), 4873 ThisNode,Value,ValueView,i,Allocator).IndexCtorMixin))){ 4874 enum result = IndexedBy.Indices[i].Inner!(typeof(this), 4875 ThisNode,Value, ValueView,i,Allocator).IndexCtorMixin ~ 4876 ForEachCtorMixin!(i+1).result; 4877 }else enum result = ForEachCtorMixin!(i+1).result; 4878 }else enum result = ""; 4879 } 4880 4881 this(){ 4882 mixin(ForEachCtorMixin!(0).result); 4883 } 4884 4885 void dealloc(ThisNode* node){ 4886 // disconnect signals from slots 4887 foreach(i, x; NormSignals.Mixin2Index){ 4888 foreach(j, malias; OU!(string).arr2tuple!(x.MixinAliases)){ 4889 static if(malias == ""){ 4890 mixin(Replace!(q{ 4891 node.value.disconnect(&node.slot$i); 4892 }, "$i", i)); 4893 }else{ 4894 mixin(Replace!(q{ 4895 node.value.$alias.disconnect(&node.slot$i); 4896 }, "$i", i,"$alias", malias)); 4897 } 4898 } 4899 } 4900 object.destroy(node); 4901 Allocator.deallocate(node); 4902 } 4903 4904 new(size_t sz) { 4905 void* p = Allocator.allocate!void(sz); 4906 return p; 4907 } 4908 delete(void* p) { 4909 Allocator.deallocate(p); 4910 } 4911 4912 template ForEachIndex(size_t N,L...){ 4913 static if(L.length > 0){ 4914 enum result = 4915 Replace!(q{ 4916 alias IndexedBy.Indices[$N] L$N; 4917 alias L$N.Inner!(typeof(this),ThisNode,Value, ValueView,$N,Allocator) M$N; 4918 mixin M$N.IndexMixin!(M$N.IndexTuple) index$N; 4919 template index(size_t n) if(n == $N){ alias index$N index; } 4920 struct Index$N{ 4921 MultiIndexContainer _this; 4922 4923 // grr opdispatch not handle this one 4924 auto opSlice(T...)(T ts){ 4925 return _this.index!($N).opSlice(ts); 4926 } 4927 4928 // grr opdispatch not handle this one 4929 auto opIndex(T...)(T ts){ 4930 return _this.index!($N).opIndex(ts); 4931 } 4932 4933 // grr opdispatch not handle this one 4934 auto opIndexAssign(T...)(T ts){ 4935 return _this.index!($N).opIndexAssign(ts); 4936 } 4937 4938 // grr opdispatch not handle this one 4939 auto opBinaryRight(string op, T...)(T ts){ 4940 return _this.index!($N).opBinaryRight!(op)(ts); 4941 } 4942 4943 // grr opdispatch not handle this one 4944 auto bounds(string bs = "[]", T)(T t1, T t2){ 4945 return _this.index!($N).bounds!(bs,T)(t1,t2); 4946 } 4947 // grr opdispatch not handle this one 4948 auto bounds(V, string bs = "[]", T)(T t1, T t2){ 4949 return _this.index!($N).cbounds!(V,bs,T)(t1,t2); 4950 } 4951 // grr opdispatch not handle this one 4952 auto cEqualRange(L, K)(K k) 4953 { 4954 return _this.index!($N).cEqualRange!(L, K).equalRange(k); 4955 } 4956 // grr opdispatch not handle this one 4957 auto cEqualRange(L, K)(K k) const 4958 { 4959 return _this.index!($N).cEqualRange!(L, K).equalRange(k); 4960 } 4961 4962 auto opDispatch(string s, T...)(T args){ 4963 mixin("return _this.index!($N)."~s~"(args);"); 4964 } 4965 } 4966 @property Index$N get_index(size_t n)() if(n == $N){ 4967 return Index$N(this); 4968 } 4969 }, "$N", N) ~ 4970 ForEachIndex!(N+1, L[1 .. $]).result; 4971 }else{ 4972 enum result = ""; 4973 } 4974 } 4975 4976 enum stuff = (ForEachIndex!(0, IndexedBy.Indices).result); 4977 mixin(stuff); 4978 4979 template ForEachNamedIndex(size_t i){ 4980 static if(i >= IndexedBy.Names.length) { 4981 enum result = ""; 4982 }else { 4983 enum result = Replace!(q{ 4984 alias get_index!$N $name; 4985 }, "$N", IndexedBy.NameIndices[i], "$name", IndexedBy.Names[i]) ~ 4986 ForEachNamedIndex!(i+1).result; 4987 } 4988 } 4989 4990 enum named_stuff = ForEachNamedIndex!0 .result; 4991 mixin(named_stuff); 4992 4993 4994 template ForEachCheckInsert(size_t i, size_t N){ 4995 static if(i < IndexedBy.Indices.length){ 4996 static if(i != N && __traits(hasMember, index!i,"_DenyInsertion")){ 4997 enum result = (Replace!(q{ 4998 ThisNode* aY; 4999 bool bY = index!(Y)._DenyInsertion(node,aY); 5000 if (bY) goto denied; 5001 }, "Y", i)) ~ ForEachCheckInsert!(i+1, N).result; 5002 }else enum result = ForEachCheckInsert!(i+1, N).result; 5003 }else enum result = ""; 5004 } 5005 5006 template ForEachDoInsert(size_t i, size_t N){ 5007 static if(i < IndexedBy.Indices.length){ 5008 static if(i != N){ 5009 import std.traits; 5010 static if(ParameterTypeTuple!(index!i._Insert).length == 2){ 5011 enum result = Replace!(q{ 5012 index!(Y)._Insert(node,aY); 5013 }, "Y", i) ~ ForEachDoInsert!(i+1,N).result; 5014 }else{ 5015 enum result = Replace!(q{ 5016 index!(Y)._Insert(node); 5017 }, "Y", i) ~ ForEachDoInsert!(i+1,N).result; 5018 } 5019 }else enum result = ForEachDoInsert!(i+1, N).result; 5020 }else enum result = ""; 5021 } 5022 5023 ThisNode* _InsertAllBut(size_t N)(Value value){ 5024 ThisNode* node = Allocator.allocate!(ThisNode)(1); 5025 static if(MutableValue!(ThisNode, Value)) { 5026 node.value = value; 5027 }else{ 5028 auto t = ThisNode(value); 5029 move(t, *node); 5030 } 5031 5032 // connect signals to slots 5033 foreach(i, x; NormSignals.Mixin2Index){ 5034 static if(i == 0) node.container = this; 5035 5036 foreach(j, malias; OU!(string).arr2tuple!(x.MixinAliases)){ 5037 static if(malias == ""){ 5038 mixin(Replace!(q{ 5039 node.value.connect(&node.slot$i); 5040 }, "$i", i)); 5041 }else{ 5042 mixin(Replace!(q{ 5043 node.value.$alias.connect(&node.slot$i); 5044 }, "$i", i,"$alias", malias)); 5045 } 5046 } 5047 } 5048 5049 // check with each index about insert op 5050 /+ 5051 foreach(i, x; IndexedByList){ 5052 /+ 5053 static if(i != N && is(typeof({ ThisNode* p; 5054 index!i._DenyInsertion(p,p);}))){ 5055 enum result = (Replace!(q{ 5056 ThisNode* aY; 5057 bool bY = index!(Y)._DenyInsertion(node,aY); 5058 if (bY) goto denied; 5059 }, "Y", i)) ~ ForEachCheckInsert!(i+1, N).result; 5060 }kelse enum result = ForEachCheckInsert!(i+1, N).result; 5061 +/ 5062 } 5063 +/ 5064 mixin(ForEachCheckInsert!(0, N).result); 5065 // perform insert op on each index 5066 mixin(ForEachDoInsert!(0, N).result); 5067 node_count++; 5068 return node; 5069 denied: 5070 return null; 5071 } 5072 5073 template ForEachDoRemove(size_t i, size_t N){ 5074 static if(i < IndexedBy.Indices.length){ 5075 static if(i != N){ 5076 enum result = Replace!(q{ 5077 index!(Y)._Remove(node); 5078 }, "Y", i) ~ ForEachDoRemove!(i+1,N).result; 5079 }else enum result = ForEachDoRemove!(i+1, N).result; 5080 }else enum result = ""; 5081 } 5082 5083 // disattach node from all indices except index N 5084 void _RemoveAllBut(size_t N)(ThisNode* node){ 5085 mixin(ForEachDoRemove!(0, N).result); 5086 node_count --; 5087 } 5088 5089 // disattach node from all indices. 5090 // @@@BUG@@@ cannot pass length directly to _RemoveAllBut 5091 auto _RemoveAll(size_t N = size_t.max)(ThisNode* node){ 5092 static if(N == size_t.max) { 5093 enum _grr_bugs = IndexedBy.Indices.length; 5094 _RemoveAllBut!(_grr_bugs)(node); 5095 }else { 5096 _RemoveAllBut!N(node); 5097 auto res = index!N._Remove(node); 5098 } 5099 dealloc(node); 5100 5101 static if(N != size_t.max) { 5102 return res; 5103 } 5104 } 5105 5106 template ForEachIndexPosition(size_t i){ 5107 static if(i < IndexedBy.Indices.length){ 5108 static if(is(typeof(index!i ._NodePosition((ThisNode*).init)))){ 5109 enum variableDeclarations = Replace!(q{ 5110 ThisNode* node$i; 5111 }, "$i", i) ~ ForEachIndexPosition!(i+1).variableDeclarations; 5112 enum getNodePositions = Replace!(q{ 5113 auto pos$i = index!$i ._NodePosition(node); 5114 }, "$i", i) ~ ForEachIndexPosition!(i+1).getNodePositions; 5115 enum gotoDeniedOnInvalid = Replace!(q{ 5116 if(!index!$i ._PositionFixable(node, pos$i, node$i)) 5117 goto denied; 5118 }, "$i", i) ~ ForEachIndexPosition!(i+1).gotoDeniedOnInvalid; 5119 enum fixupIndices = Replace!(q{ 5120 index!$i ._FixPosition(node, pos$i, node$i); 5121 }, "$i", i) ~ ForEachIndexPosition!(i+1).fixupIndices; 5122 }else{ 5123 enum getNodePositions = ForEachIndexPosition!(i+1).getNodePositions; 5124 enum variableDeclarations = ForEachIndexPosition!(i+1).variableDeclarations; 5125 enum gotoDeniedOnInvalid = ForEachIndexPosition!(i+1).gotoDeniedOnInvalid; 5126 enum fixupIndices = ForEachIndexPosition!(i+1).fixupIndices; 5127 } 5128 }else{ 5129 enum getNodePositions = ""; 5130 enum variableDeclarations = ""; 5131 enum gotoDeniedOnInvalid = ""; 5132 enum fixupIndices = ""; 5133 } 5134 } 5135 5136 bool _Replace(ThisNode* node, Value value){ 5137 mixin(ForEachIndexPosition!0 .variableDeclarations); 5138 mixin(ForEachIndexPosition!0 .getNodePositions); 5139 Value old = node.value; 5140 node.value = value; 5141 { 5142 mixin(ForEachIndexPosition!0 .gotoDeniedOnInvalid); 5143 mixin(ForEachIndexPosition!0 .fixupIndices); 5144 } 5145 return true; 5146 denied: 5147 node.value = old; 5148 return false; 5149 } 5150 5151 /* 5152 Perform mod on node.value and perform any necessary fixups to this container's 5153 indices. mod may be of the form void mod(ref Value), in which case mod directly modifies the value in node. If the result of mod violates any index' invariant, 5154 the node is removed from the container. 5155 Preconditions: mod is a callable of the form void mod(ref Value) 5156 Complexity: $(BIGOH m(n)) 5157 */ 5158 void _Modify(Modifier)(ThisNode* node, Modifier mod){ 5159 mixin(ForEachIndexPosition!0 .variableDeclarations); 5160 mixin(ForEachIndexPosition!0 .getNodePositions); 5161 mod(node.value); 5162 mixin(ForEachIndexPosition!0 .gotoDeniedOnInvalid); 5163 mixin(ForEachIndexPosition!0 .fixupIndices); 5164 return; 5165 denied: 5166 _RemoveAll(node); 5167 } 5168 5169 template ForEachClear(size_t i){ 5170 static if(i < IndexedBy.Indices.length){ 5171 enum string result = Replace!(q{ 5172 index!$i ._ClearIndex(); 5173 }, "$i", i) ~ ForEachClear!(i+1).result; 5174 }else enum string result = ""; 5175 } 5176 5177 void _Clear(){ 5178 auto r = index!0 .opSlice(); 5179 while(!r.empty){ 5180 ThisNode* node = r.front_node; 5181 r.popFront(); 5182 dealloc(node); 5183 } 5184 mixin(ForEachClear!0 .result); 5185 node_count = 0; 5186 } 5187 5188 template ForEachCheck(size_t i){ 5189 static if(i < IndexedBy.Indices.length){ 5190 enum result = Replace!(q{ 5191 index!($i)._Check(); 5192 },"$i", i) ~ ForEachCheck!(i+1).result; 5193 }else{ 5194 enum result = ""; 5195 } 5196 } 5197 5198 void check(){ 5199 mixin(ForEachCheck!(0).result); 5200 } 5201 5202 template ForEachAlias(size_t N,size_t index, alias X){ 5203 alias X.Inner!(ThisNode,Value, ValueView,N,Allocator).Index!() Index; 5204 static if(Index.container_aliases.length > index){ 5205 enum aliashere = NAliased!(Index.container_aliases[index][0], 5206 Index.container_aliases[index][1], N); 5207 enum result = aliashere ~ "\n" ~ ForEachAlias!(N,index+1, X).result; 5208 }else{ 5209 enum result = ""; 5210 } 5211 } 5212 5213 5214 @property auto to_range(size_t N, Range0)(Range0 r) 5215 if(RangeIndexNo!Range0 != -1){ 5216 static if(N == RangeIndexNo!Range0){ 5217 return r; 5218 }else{ 5219 return index!N.fromNode(r.front_node); 5220 } 5221 } 5222 5223 private template RangeIndexNo(R){ 5224 template IndexNoI(size_t i){ 5225 static if(i == IndexedBy.Indices.length){ 5226 enum size_t IndexNoI = -1; 5227 }else static if(index!(i).IsMyRange!(R)){ 5228 enum size_t IndexNoI = i; 5229 }else{ 5230 enum IndexNoI = IndexNoI!(i+1); 5231 } 5232 } 5233 enum size_t RangeIndexNo = IndexNoI!(0); 5234 } 5235 } 5236 5237 /// simple Slot implementation 5238 mixin template Slots() { 5239 void delegate()[] slots; 5240 5241 void connect(void delegate() slot){ 5242 slots ~= slot; 5243 } 5244 void disconnect(void delegate() slot){ 5245 size_t index = slots.length; 5246 foreach(i, slot1; slots){ 5247 if(slot is slot1){ 5248 index = i; 5249 moveAll(slots[i+1 .. $], slots[i .. $-1]); 5250 slots.length-=1; 5251 break; 5252 } 5253 } 5254 } 5255 void emit(){ 5256 foreach(slot; slots){ 5257 slot(); 5258 } 5259 } 5260 } 5261 5262 import std.stdio; 5263 5264 int[] arr(Range)(Range r){ 5265 int[] result = new int[](r.length); 5266 size_t j = 0; 5267 foreach(e; r){ 5268 result[j++] = e; 5269 } 5270 return result; 5271 } 5272 5273 struct S1{ 5274 string _s; 5275 int _i; 5276 void delegate() slot = null; 5277 5278 @property string s()const{ return _s;} 5279 @property void s(string s_){ _s = s_; emit(); } 5280 5281 @property int i()const{ return _i;} 5282 @property void i(int i_){ _i = i_; } 5283 5284 void emit(){ 5285 if (slot) slot(); 5286 } 5287 5288 void connect(void delegate() slot){ this.slot = slot; } 5289 void disconnect(void delegate() slot){ 5290 if(this.slot is slot) this.slot = null; 5291 } 5292 5293 string toString0()const{ 5294 return format("%s: %s", s, i); 5295 } 5296 } 5297 5298 version(TestMultiIndex) 5299 void main(){ 5300 alias MultiIndexContainer!(S1, 5301 IndexedBy!(Sequenced!(), 5302 OrderedUnique!("a.s") 5303 ), 5304 ValueChangedSlots!(ValueSignal!(1))) C; 5305 5306 C i = new C; 5307 5308 alias MultiIndexContainer!(const(S1), 5309 IndexedBy!(OrderedUnique!("a.s")) 5310 ) CCC; 5311 CCC c2 = new CCC; 5312 c2.insert(cast(const)S1("abc", 22)); 5313 pragma(msg, typeof(c2[])); 5314 pragma(msg, ElementType!(typeof(c2[]))); 5315 foreach(const(S1) thing; c2[]) { 5316 } 5317 5318 auto pr = PSR(c2[]); 5319 c2.replace(pr.front, const(S1)("def", 44)); 5320 }