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