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 }