View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript-Util: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2005 Open World Ltd, Kevin Rogers
4   //
5   // This file is part of MillScript-Util.
6   //
7   // MillScript-Util is free software; you can redistribute it and/or modify it under
8   // the terms of the GNU General Public License as published by the Free
9   // Software Foundation; either version 2 of the License, or (at your option)
10  // any later version.
11  //
12  // MillScript-Util is distributed in the hope that it will be useful, but WITHOUT
13  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  // more details.
16  //
17  // You should have received a copy of the GNU General Public License along with
18  // MillScript-Util; if not, write to the Free Software Foundation, Inc., 59 Temple
19  // Place, Suite 330, Boston, MA  02111-1307  USA
20  ////////////////////////////////////////////////////////////////////////////////
21  package org.millscript.commons.util.map;
22  
23  import java.io.IOException;
24  import java.io.ObjectInputStream;
25  import java.io.ObjectOutputStream;
26  import java.io.Serializable;
27  
28  import org.millscript.commons.alert.alerts.Fault;
29  import org.millscript.commons.util.IList;
30  import org.millscript.commons.util.IMap;
31  import org.millscript.commons.util.ListIterator;
32  import org.millscript.commons.util.MapIterator;
33  import org.millscript.commons.util.Maplet;
34  import org.millscript.commons.util.alerts.ListIndexOutOfBoundsAlert;
35  import org.millscript.commons.util.alerts.NoSuchKeyInMapAlert;
36  import org.millscript.commons.util.iterator.AbstractListIterator;
37  import org.millscript.commons.util.iterator.AbstractMapIterator;
38  import org.millscript.commons.util.iterator.ArrayListIterator;
39  import org.millscript.commons.util.list.AbstractIList;
40  import org.millscript.commons.util.list.IArrayList;
41  
42  /**
43   * 
44   */
45  public class EBinaryTreeMap< K extends Comparable< K >, V > extends AbstractEMap< K, V > implements Cloneable, Serializable {
46  
47      /**
48       * This is the ID from the release 0.1.0 for future compatibility.
49       */
50      private static final long serialVersionUID = 5434674165103600680L;
51  
52      public static class Node< K extends Comparable< K >, V > implements Maplet< K, V > {
53  
54          /**
55           * The height of the tree at this point, i.e. the largest numer of
56           * child nodes to a leaf. A short allows for a maximum height of 32767
57           * nodes(without trying to use the negatives) allowing around 500
58           * million entries in the map. 
59           */
60          private short height;
61  
62          /**
63           * The size of the tree at this point, i.e. the number of nodes
64           * including this one and its children.
65           */
66          int size;
67  
68          /**
69           * The maplet key stored at this node.
70           */
71          final K key;
72  
73          /**
74           * The left child node.
75           */
76          Node< K, V > left;
77  
78          /**
79           * The parent node.
80           */
81          Node< K, V > parent;
82  
83          /**
84           * The right child node.
85           */
86          Node< K, V > right;
87  
88          /**
89           * The maplet value stored at this node.
90           */
91          V value;
92  
93          public Node( final Node< K, V > p, final K k, final V v ) {
94              // This new node has no children, so it's height is zero
95              this.height = 0;
96              this.key = k;
97              this.parent = p;
98              // This new node has no children, so it's size is one
99              this.size = 1;
100             this.value = v;
101         }
102 
103         public Node( final Node< K, V > p, final K[] keys, final V[] values, final int first, final int last ) {
104             this.parent = p;
105             // The index of the central element within the slice is half the
106             // length of the array, rounding up. To avoid calling methods we
107             // use an integer math version, where we take the length of the
108             // array, subtract one, halve, then add one to get the central
109             // index. e.g. the variable keys is an array type, so the central
110             // index is
111             // ( ( keys.length - 1 ) / 2 ) + 1;
112             // which gives us the one based index to the central element within
113             // the slice, so we skip adding the final one.
114             // To get the index into the whole array we must add to the first
115             // index and adjust for the one/zero based indexing.
116             final int zeroBasedCentralIndex = ( last + first - 1 ) / 2;
117             this.key = (K) keys[ zeroBasedCentralIndex ];
118             this.value = (V) values[ zeroBasedCentralIndex ];
119             // NOTE - Technically we should subtract one from the one-based
120             // central index, but as the earlier calculation gives us the zero
121             // based index we can use that directly as the index of the last
122             // element in the slice of the array for the left branch
123             // Are there any elements left on the left?
124             if ( zeroBasedCentralIndex >= first ) {
125                 // Yes there are...
126                 this.left = new Node< K, V >( this, keys, values, first, zeroBasedCentralIndex );
127             }
128             // NOTE - We add two here as we use a zero based central index, but
129             // a one based first/last index
130             final int lastRight = zeroBasedCentralIndex + 2;
131             // Are there any elements left on the right?
132             if ( lastRight <= last ) {
133                 // Yes there are...
134                 this.right = new Node< K, V >( this, keys, values, lastRight, last );
135             }
136             // We have to update the size on the way out...
137             this.updateSize();
138         }
139 
140         public Node< K, V > deepCopy() {
141             final Node< K, V > copy = new Node< K, V >( this.parent, this.key, this.value );
142             if ( this.left != null ) {
143                 copy.left = this.left.deepCopy();
144             }
145             if ( this.right != null ) {
146                 copy.right = this.right.deepCopy();
147             }
148             copy.updateSize();
149             return copy;
150         }
151 
152         public Node< K, V > getLeftmost() {
153             Node< K, V > leftmost = this;
154             while ( leftmost.left != null ) {
155                 leftmost = leftmost.left;
156             }
157             return leftmost;
158         }
159 
160         public Node< K, V > getNextInSequence() {
161             // Must advance to the next node if available.
162             if ( this.right == null ) {
163                 if ( this.parent == null ) {
164                     // We're at the top of the tree and there's nothing on
165                     // the right, so we're done.
166                     return null;
167                 } else {
168                     // Ok, there's nothing to the right so we have to go up
169                     // the tree to our parent
170                     Node< K, V > nextNode = this.parent;
171                     // Check if the current node is the rightmost node of
172                     // the branch
173                     if ( this == this.parent.right ) {
174                         // It is, so go up the tree until we find an
175                         // element that is the left child of its parent and
176                         // choose that parent.
177                         while ( nextNode.parent != null && nextNode == nextNode.parent.right ) {
178                             nextNode = nextNode.parent;
179                         }
180                         nextNode = nextNode.parent;
181                     }
182                     return nextNode;
183                 }
184             } else {
185                 Node< K, V > nextNode = this.right;
186                 while ( nextNode.left != null ) {
187                     nextNode = nextNode.left;
188                 }
189                 return nextNode;
190             }
191         }
192 
193         public K getKey() {
194             return this.key;
195         }
196 
197         public V getValue() {
198             return this.value;
199         }
200 
201         public void insertPushLeft( final EBinaryTreeMap< K, V > map, final K k, final V v ) {
202             // 1) Initialise the new node
203             final Node< K, V > replacementNode = new Node< K, V >( this.parent, k, v );
204             replacementNode.left = this;
205             replacementNode.right = this.right;
206             // 2) Put the replacement node in place
207             if ( this.parent == null ) {
208                 map.root = replacementNode;
209             } else if ( this == this.parent.left ) {
210                 this.parent.left = replacementNode;
211             } else {
212                 this.parent.right = replacementNode;
213             }
214             this.parent = replacementNode;
215             this.right.parent = replacementNode;
216             this.right = null;
217             // 3) Update the sizes for this node, the old parent
218             // and the new nodes
219             this.updateSize();
220             // Set the new nodes size
221             replacementNode.updateSize();
222         }
223 
224         public void insertPushRight( final EBinaryTreeMap< K, V > map, final K k, final V v ) {
225             // 1) Initialise the new node
226             final Node< K, V > replacementNode = new Node< K, V >( this.parent, k, v );
227             replacementNode.left = this.left;
228             replacementNode.right = this;
229             // 2) Put the replacement node in place
230             if ( this.parent == null ) {
231                 map.root = replacementNode;
232             } else if ( this == this.parent.left ) {
233                 this.parent.left = replacementNode;
234             } else {
235                 this.parent.right = replacementNode;
236             }
237             this.parent = replacementNode;
238             this.left.parent = replacementNode;
239             this.left = null;
240             // 3) Update the sizes for this node, the old parent
241             // and the new nodes
242             this.updateSize();
243             // Set the new nodes size
244             replacementNode.updateSize();
245         }
246 
247         protected Node< K, V > remove( final EBinaryTreeMap< K, V > map ) {
248             if ( this.left == null ) {
249                 if ( this.parent == null ) {
250                     // Delete this node by moving its right to be the root
251                     map.root = this.right;
252                 } else if ( this == this.parent.left ) {
253                     this.parent.left = this.right;
254                 } else {
255                     this.parent.right = this.right;
256                 }
257                 if ( this.right == null ) {
258                     return this.parent;
259                 } else {
260                     this.right.parent = this.parent;
261                     return this.right;
262                 }
263             } else if ( this.right == null ) {
264                 // Delete this node by moving its left to be the
265                 // root
266                 if ( this.parent == null ) {
267                     // Delete this node by moving its right to be the root
268                     map.root = this.left;
269                 } else if ( this == this.parent.left ) {
270                     this.parent.left = this.left;
271                 } else {
272                     this.parent.right = this.left;
273                 }
274                 if ( this.left == null ) {
275                     return this.parent;
276                 } else {
277                     this.left.parent = this.parent;
278                     return this.left;
279                 }
280             } else if ( Math.random() < 0.5d ) {
281                 // Ok there is a left and right, so we've randomly
282                 // chosen to move the right
283                 // NOTE - At this point the left and right are not null
284                 Node< K, V > replacement = this.right;
285                 while ( replacement.left != null ) {
286                     replacement = replacement.left;
287                 }
288                 if ( this.parent == null ) {
289                     // Delete this node by moving its right to be the root
290                     map.root = replacement;
291                 } else if ( this == this.parent.left ) {
292                     this.parent.left = replacement;
293                 } else {
294                     this.parent.right = replacement;
295                 }
296                 if ( replacement == this.right ) {
297                     // Ok we will replace this node with our right(which has no
298                     // left children)
299                     replacement.left = this.left;
300                     this.left.parent = replacement;
301                     replacement.parent = this.parent;
302                 } else {
303                     // We will replace this node with the leftmost child of the
304                     // right node
305                     replacement.left = this.left;
306                     this.left.parent = replacement;
307                     // The replacement is the left child of its parent
308                     replacement.parent.left = replacement.right;
309                     if ( replacement.right != null ) {
310                         replacement.right.parent = replacement.parent;
311                     }
312                     Node< K, V > fixsizeFromHere = replacement.parent;
313                     replacement.parent = this.parent;
314                     replacement.right = this.right;
315                     this.right.parent = replacement;
316                     for ( ; fixsizeFromHere != null; fixsizeFromHere = fixsizeFromHere.parent ) {
317                         fixsizeFromHere.updateSize();
318                     }
319                 }
320                 return replacement;
321             } else {
322                 // Ok there is a left and right, so we've randomly
323                 // chosen to move the left
324                 // NOTE - At this point the left and right are not null
325                 Node< K, V > replacement = this.left;
326                 while ( replacement.right != null ) {
327                     replacement = replacement.right;
328                 }
329                 if ( this.parent == null ) {
330                     // Delete this node by moving its right to be the root
331                     map.root = replacement;
332                 } else if ( this == this.parent.left ) {
333                     this.parent.left = replacement;
334                 } else {
335                     this.parent.right = replacement;
336                 }
337                 if ( replacement == this.left ) {
338                     // Ok we will replace this node with our left(which has no
339                     // right children)
340                     replacement.right = this.right;
341                     this.right.parent = replacement;
342                     replacement.parent = this.parent;
343                 } else {
344                     // We will replace this node with the leftmost child of the
345                     // right node
346                     replacement.right = this.right;
347                     this.right.parent = replacement;
348                     // The replacement is the right child of its parent
349                     replacement.parent.right = replacement.left;
350                     if ( replacement.left != null ) {
351                         replacement.left.parent = replacement.parent;
352                     }
353                     Node< K, V > fixsizeFromHere = replacement.parent;
354                     replacement.parent = this.parent;
355                     replacement.left = this.left;
356                     this.left.parent = replacement;
357                     for ( ; fixsizeFromHere != null; fixsizeFromHere = fixsizeFromHere.parent ) {
358                         fixsizeFromHere.updateSize();
359                     }
360                 }
361                 return replacement;
362             }
363         }
364 
365         public void rotateLeft( final EBinaryTreeMap< K, V > map ) {
366             // 1) Set the parent of the right element to our parent
367             this.right.parent = this.parent;
368             // 2) Update our parent(if there is one) to point to its new child,
369             // our right element
370             if ( this.parent == null ) {
371                 map.root = this.right;
372             } else {
373                 if ( this == this.parent.left ) {
374                     this.parent.left = this.right;
375                 } else {
376                     this.parent.right = this.right;
377                 }
378             }
379             // 3) Update our parent node so it points to it's new parent
380             this.parent = this.right;
381             // 4) Store a reference to the node being moved
382             final Node< K, V > onTheMove = this.right.left;
383             // 5) Move this node to the left child of the (old) right node
384             this.right.left = this;
385             // 6) Move the left child of the old right node to the right child
386             // of this one.
387             this.right = onTheMove;
388             if ( onTheMove != null ) {
389                 onTheMove.parent = this;
390             }
391             // 7) Update the sizes for this node and the old parent
392             this.updateSize();
393             this.parent.updateSize();
394         }
395 
396         public void rotateRight( final EBinaryTreeMap< K, V > map ) {
397             // 1) Set the parent of the left element to our parent
398             this.left.parent = this.parent;
399             // 2) Update our parent(if there is one) to point to its new child,
400             // our left element
401             if ( this.parent == null ) {
402                 map.root = this.left;
403             } else {
404                 if ( this == this.parent.left ) {
405                     this.parent.left = this.left;
406                 } else {
407                     this.parent.right = this.left;
408                 }
409             }
410             // 3) Update our parent node so it points to it's new parent
411             this.parent = this.left;
412             // 4) Store a reference to the node being moved
413             final Node< K, V > onTheMove = this.left.right;
414             // 5) Move this node to the right child of the (old) left node
415             this.left.right = this;
416             // 6) Move the right child of the old left node to the left child
417             // of this one.
418             this.left = onTheMove;
419             if ( onTheMove != null ) {
420                 onTheMove.parent = this;
421             }
422             // 7) Update the sizes for this node and the old parent
423             this.updateSize();
424             this.parent.updateSize();
425         }
426 
427         protected void updateSize() {
428             if ( this.left == null ) {
429                 if ( this.right == null ) {
430                     this.size = 1;
431                 } else {
432                     this.size = 1 + this.right.size;
433                 }
434             } else {
435                 if ( this.right == null ) {
436                     this.size = 1 + this.left.size;
437                 } else {
438                     this.size = 1 + this.left.size + this.right.size;
439                 }
440             }
441         }
442 
443     }
444 
445     public static class NodeIterator< K extends Comparable< K >, V > extends AbstractMapIterator< K, V > {
446 
447         /**
448          * The current node in the iteration.
449          */
450         private Node< K, V > currentNode;
451 
452         /**
453          * The next node in the iteration, if this is null 
454          */
455         private Node< K, V > nextNode;
456 
457         /**
458          * Constructs a new binary tree map iterator to iterate over the specified
459          * node tree.
460          *
461          * @param rootNode  the root node in the tree to iterate over 
462          * @param share if <code>true</code> the specified node tree will be
463          * shared otherwise the array will be copied.
464          */
465         public NodeIterator( final Node< K, V > rootNode, final boolean share ) {
466             if ( rootNode != null ) {
467                 if ( share ) {
468                     this.nextNode = rootNode.getLeftmost();
469                 } else {
470                     this.nextNode = rootNode.deepCopy().getLeftmost();
471                 }
472             }
473         }
474 
475         /**
476          * @see org.millscript.commons.util.iterator.AbstractMapIterator#advance()
477          */
478         @Override
479         protected void advance() {
480             // Ensure the next node is properly populated
481             this.checkNext();
482             // Move to the next node
483             this.currentNode = this.nextNode;
484             this.nextNode = null;
485         }
486 
487         /**
488          * Checks that the next maplet field is populated with the next maplet
489          * if one is available.
490          */
491         private void checkNext() {
492             if ( this.nextNode == null && this.currentNode != null ) {
493                 this.nextNode = this.currentNode.getNextInSequence();
494             }
495         }
496 
497         /**
498          * @see org.millscript.commons.util.iterator.AbstractMapIterator#getKey()
499          */
500         @Override
501         protected K getKey() {
502             return this.currentNode.key;
503         }
504 
505         /**
506          * @see org.millscript.commons.util.iterator.AbstractMapIterator#getMaplet()
507          */
508         @Override
509         protected Maplet< K, V > getMaplet() {
510             return this.currentNode;
511         }
512 
513         /**
514          * @see org.millscript.commons.util.iterator.AbstractMapIterator#getValue()
515          */
516         @Override
517         protected V getValue() {
518             return this.currentNode.value;
519         }
520 
521         /**
522          * @see org.millscript.commons.util.MapIterator#hasNext()
523          */
524         public boolean hasNext() {
525             this.checkNext();
526             return this.nextNode != null;
527         }
528 
529         /**
530          * @see org.millscript.commons.util.iterator.AbstractMapIterator#outOfBounds()
531          */
532         @Override
533         protected boolean outOfBounds() {
534             return this.currentNode == null;
535         }
536 
537     }
538 
539     public static class NodeKeyIterator< K extends Comparable< K > > extends NodeXIterator< K > {
540 
541         /**
542          * Constructs a new binary tree map iterator to iterate over the specified
543          * node tree.
544          *
545          * @param node  any node in the leftmost branch of the backing store
546          * tree
547          * @param num   the number of elements in this iteration
548          */
549         protected NodeKeyIterator( final Node< ?, ? > node, final int num ) {
550             super( node, num );
551         }
552 
553         /**
554          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXIterator#getAppropriateNodePart(org.millscript.commons.util.map.EBinaryTreeMap.Node)
555          */
556         @Override
557         @SuppressWarnings( "unchecked" )
558         K getAppropriateNodePart( final Node< ?, ? > node ) {
559             return (K) node.getKey();
560         }
561         
562     }
563     
564     public static class NodeKeyList< K extends Comparable< K > > extends NodeXList< K > {
565 
566         /**
567          * Constructs a new immutable list of the keys in the specified node
568          * tree.
569          *
570          * @param node  any node in the leftmost branch of the backing store
571          * tree
572          * @param start the index(one based, inclusive) to start iterating from
573          * @param end   the index(one based, inclusive) to stop iterating at
574          */
575         protected NodeKeyList( final Node< ?, ? > node, final int start, final int end ) {
576             super( node, start, end );
577         }
578 
579         /**
580          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXList#getAppropriateNodePart(org.millscript.commons.util.map.EBinaryTreeMap.Node)
581          */
582         @Override
583         @SuppressWarnings( "unchecked" )
584         K getAppropriateNodePart( final Node< ?, ? > node ) {
585             return (K) node.getKey();
586         }
587 
588         /**
589          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXList#sharedIterator()
590          */
591         @Override
592         public ListIterator< K > sharedIterator() {
593             return new NodeKeyIterator< K >(
594                 this.firstNode,
595                 this.size
596             );
597         }
598         
599         /**
600          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXList#sharedSlice(int, int)
601          */
602         @Override IList< K > sharedSlice( final int first, final int last ) {
603             return new NodeKeyList< K >(
604                 this.firstNode,
605                 this.firstIndex + first - 1,
606                 this.firstIndex + last - 1
607             );
608         }
609         
610     }
611 
612     public static class NodeMapletIterator< K extends Comparable< K >, V > extends NodeXIterator< Maplet< K, V > > {
613 
614         /**
615          * Constructs a new binary tree map iterator to iterate over the specified
616          * node tree.
617          *
618          * @param node  any node in the leftmost branch of the backing store
619          * tree
620          * @param num   the number of elements in this iteration
621          */
622         protected NodeMapletIterator( final Node< ?, ? > node, final int num ) {
623             super( node, num );
624         }
625 
626         /**
627          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXIterator#getAppropriateNodePart(org.millscript.commons.util.map.EBinaryTreeMap.Node)
628          */
629         @Override
630         @SuppressWarnings( "unchecked" )
631         Maplet< K, V > getAppropriateNodePart( final Node< ?, ? > node ) {
632             return (Maplet< K, V >) node;
633         }
634         
635     }
636     
637     public static class NodeMapletList< K extends Comparable< K >, V > extends NodeXList< Maplet< K, V > > {
638 
639         /**
640          * Constructs a new immutable list of the maplets in the specified node
641          * tree.
642          *
643          * @param node  any node in the leftmost branch of the backing store
644          * tree
645          * @param start the index(one based, inclusive) to start iterating from
646          * @param end   the index(one based, inclusive) to stop iterating at
647          */
648         protected NodeMapletList( final Node< ?, ? > node, final int start, final int end ) {
649             super( node, start, end );
650         }
651 
652         /**
653          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXList#getAppropriateNodePart(org.millscript.commons.util.map.EBinaryTreeMap.Node)
654          */
655         @Override
656         @SuppressWarnings( "unchecked" )
657         Maplet< K, V > getAppropriateNodePart( final Node< ?, ? > node ) {
658             return (Maplet<K, V>) node;
659         }
660         
661         /**
662          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXList#sharedIterator()
663          */
664         @Override
665         public ListIterator< Maplet< K, V > > sharedIterator() {
666             return new NodeMapletIterator< K, V >(
667                 this.firstNode,
668                 this.size
669             );
670         }
671         
672         /**
673          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXList#sharedSlice(int, int)
674          */
675         @Override
676         IList< Maplet< K, V > > sharedSlice( final int first, final int last ) {
677             return new NodeMapletList< K, V >(
678                 this.firstNode,
679                 this.firstIndex + first - 1,
680                 this.firstIndex + last - 1
681             );
682         }
683         
684     }
685 
686     public static class NodeValueIterator< V > extends NodeXIterator< V > {
687 
688         /**
689          * Constructs a new binary tree map iterator to iterate over the specified
690          * node tree.
691          *
692          * @param node  any node in the leftmost branch of the backing store
693          * tree
694          * @param num   the number of elements in this iteration
695          */
696         protected NodeValueIterator( final Node< ?, ? > node, final int num ) {
697             super( node, num );
698         }
699 
700         /**
701          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXIterator#getAppropriateNodePart(org.millscript.commons.util.map.EBinaryTreeMap.Node)
702          */
703         @Override
704         @SuppressWarnings( "unchecked" )
705         V getAppropriateNodePart( final Node< ?, ? > node ) {
706             return (V) node.getValue();
707         }
708         
709     }
710     
711     public static class NodeValueList< V > extends NodeXList< V > {
712 
713         /**
714          * Constructs a new immutable list of the values in the specified node
715          * tree.
716          *
717          * @param node  any node in the leftmost branch of the backing store
718          * tree
719          * @param start the index(one based, inclusive) to start iterating from
720          * @param end   the index(one based, inclusive) to stop iterating at
721          */
722         protected NodeValueList( final Node< ?, ? > node, final int start, final int end ) {
723             super( node, start, end );
724         }
725 
726         /**
727          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXList#getAppropriateNodePart(org.millscript.commons.util.map.EBinaryTreeMap.Node)
728          */
729         @Override
730         @SuppressWarnings( "unchecked" )
731         V getAppropriateNodePart( final Node< ?, ? > node ) {
732             return (V) node.getValue();
733         }
734         
735         /**
736          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXList#sharedIterator()
737          */
738         @Override
739         public ListIterator< V > sharedIterator() {
740             return new NodeValueIterator< V >(
741                 this.firstNode,
742                 this.size
743             );
744         }
745 
746         /**
747          * @see org.millscript.commons.util.map.EBinaryTreeMap.NodeXList#sharedSlice(int, int)
748          */
749         @Override
750         IList< V > sharedSlice( final int first, final int last ) {
751             return new NodeValueList< V >(
752                 this.firstNode,
753                 this.firstIndex + first - 1,
754                 this.firstIndex + last - 1
755             );
756         }
757         
758     }
759 
760     public abstract static class NodeXIterator< E > extends AbstractListIterator< E > {
761 
762         /**
763          * The current node in the iteration.
764          */
765         private Node< ?, ? > currentNode;
766 
767         /**
768          * The next node in the iteration, if this is null 
769          */
770         private Node< ?, ? > nextNode;
771 
772         /**
773          * The list size.
774          */
775         private final int size;
776 
777         /**
778          * Constructs a new binary tree map iterator to iterate over the specified
779          * node tree.
780          *
781          * @param node  any node in the leftmost branch of the backing store
782          * tree
783          * @param num   the number of elements in this iteration
784          */
785         protected NodeXIterator( final Node< ?, ? > node, final int num ) {
786             if ( num <= 0 ) {
787                 this.nextNode = null;
788                 this.size = 0;
789             } else {
790                 this.nextNode = node;
791                 this.size = num;
792             }
793         }
794 
795         /**
796          * @see org.millscript.commons.util.iterator.AbstractMapIterator#advance()
797          */
798         @Override
799         protected void advance() {
800             // Increment the position
801             super.advance();
802             this.currentNode = this.nextNode;
803             // Check if we've reached the last element in the iteration and
804             // ensure the next node is properly populated
805             if ( super.position == this.size ) {
806                 this.nextNode = null;
807             } else if ( this.nextNode != null ) {
808                 this.nextNode = this.currentNode.getNextInSequence();
809             }
810         }
811 
812         /**
813          * Returns the appropriate part of the specified node for this list.
814          *
815          * @param node  the node to get the appropriate part from
816          * @return  the appropriate part of the specified node
817          */
818         abstract E getAppropriateNodePart( Node< ?, ? > node );
819 
820         /**
821          * @see org.millscript.commons.util.iterator.AbstractMapIterator#getValue()
822          */
823         @Override
824         protected E getValue() {
825             return this.getAppropriateNodePart( this.currentNode );
826         }
827 
828         /**
829          * @see org.millscript.commons.util.MapIterator#hasNext()
830          */
831         public boolean hasNext() {
832             return this.nextNode != null;
833         }
834 
835         /**
836          * @see org.millscript.commons.util.iterator.AbstractMapIterator#outOfBounds()
837          */
838         @Override
839         protected boolean outOfBounds() {
840             return this.currentNode == null;
841         }
842 
843     }
844 
845     public abstract static class NodeXList< E > extends AbstractIList< E > {
846 
847         /**
848          * The index of the first element.
849          */
850         final int firstIndex;
851 
852         /**
853          * The first node in the list.
854          */
855         final Node< ?, ? > firstNode;
856 
857         /**
858          * The list size.
859          */
860         final int size;
861 
862         /**
863          * Constructs a new immutable list backed by the specified node tree.
864          *
865          * @param node  any node in the leftmost branch of the backing store
866          * tree
867          * @param start the index(one based, inclusive) to start iterating from
868          * @param end   the index(one based, inclusive) to stop iterating at
869          */
870         protected NodeXList( final Node< ?, ? > node, final int start, final int end ) {
871             this.firstIndex = start;
872             if ( start > end ) {
873                 this.firstNode = null;
874                 this.size = 0;
875             } else if ( end - start + 1 > node.size ) {
876                 throw new ListIndexOutOfBoundsAlert(
877                     "Requested list exceeds bounds of specified node tree"
878                 ).culprit(
879                     "first element index",
880                     start
881                 ).culprit(
882                     "last element index",
883                     end
884                 ).decorate( node ).mishap();
885             } else {
886                 Node< ?, ? > current = node.getLeftmost();
887                 int outerListCount = 1;
888                 // Find the first link in the shared chain
889                 for ( ; outerListCount < start; outerListCount++ ) {
890                     current = current.getNextInSequence();
891                 }
892                 this.firstNode = current;
893                 this.size = end - start + 1;
894             }
895         }
896 
897         /**
898          * @see org.millscript.commons.util.list.AbstractIList#doGet(int)
899          */
900         @Override
901         protected E doGet( final int pos ) {
902             int currentPos = 1;
903             for ( Node< ?, ? > current = this.firstNode; current != null; current = current.getNextInSequence() ) {
904                 if ( pos == currentPos++ ) {
905                     return this.getAppropriateNodePart( current );
906                 }
907             }
908             throw new Fault(
909                 "Specified position is neither out of bounds or within the list!"
910             ).culprit( "index", pos ).decorate( this ).mishap();
911         }
912 
913         /**
914          * @see org.millscript.commons.util.list.AbstractIList#doSlice(int, int, boolean)
915          */
916         @Override
917         @SuppressWarnings( "unchecked" )
918         protected IList< E > doSlice( final int first, final int last, final boolean share ) {
919             if ( share ) {
920                 return this.sharedSlice( first, last );
921             } else {
922                 // Return a copy of the relevant slice of the list
923                 final E[] objects = (E[]) new Object[ first - last + 1 ];
924                 Node< ?, ? > current = this.firstNode;
925                 int outerListCount = 1;
926                 // Find the first link in the shared chain
927                 for ( ; outerListCount <= first; outerListCount++ ) {
928                     current = current.getNextInSequence();
929                 }
930                 // Now copy each required link into the array
931                 int newArrayPos = 0;
932                 for ( ; current != null && outerListCount <= last; current = current.getNextInSequence(), outerListCount++ ) {
933                     objects[ newArrayPos++ ] = this.getAppropriateNodePart( current );
934                 }
935                 return new IArrayList< E >( objects, true );
936             }
937         }
938 
939         /**
940          * Returns the appropriate part of the specified node for this list.
941          *
942          * @param node  the node to get the appropriate part from
943          * @return  the appropriate part of the specified node
944          */
945         abstract E getAppropriateNodePart( Node< ?, ? > node );
946 
947         /**
948          * @see org.millscript.commons.util.IList#indexOf(java.lang.Object)
949          */
950         public int indexOf( final E value ) {
951             int currentPos = 1;
952             for ( Node< ?, ? > current = this.firstNode; current != null; current = current.getNextInSequence() ) {
953                 if ( value == null ? this.getAppropriateNodePart( current ) == null : value.equals( this.getAppropriateNodePart( current ) ) ) {
954                     return currentPos;
955                 }
956             }
957             return 0;
958         }
959 
960         /**
961          * @see org.millscript.commons.util.IMap#iterator(boolean)
962          */
963         @SuppressWarnings( "unchecked" )
964         public ListIterator< E > iterator( final boolean share ) {
965             if ( share ) {
966                 return this.sharedIterator();
967             } else {
968                 final E[] objects = (E[]) new Object[ this.size() ];
969                 Node< ?, ? > current = this.firstNode;
970                 for ( int i = 0; current != null; i++, current = current.getNextInSequence() ) {
971                     objects[ i ] = this.getAppropriateNodePart( current );
972                 }
973                 return new ArrayListIterator< E >( objects, true );
974             }
975         }
976 
977         /**
978          * Returns a list iterator which shares backing store with this list.
979          *
980          * @return  a list iterator which shares this lists backing store
981          */
982         abstract ListIterator< E > sharedIterator();
983 
984         /**
985          * Returns a slice of this list which shares backing store with this
986          * list.
987          *
988          * @param first the index(one based) of the first element in the slice
989          * @param last  the index(one based) of the last element in the slice
990          * @return  a slice of this list which shares this lists backing store
991          */
992         abstract IList< E > sharedSlice( int first, int last );
993 
994         /**
995          * @see org.millscript.commons.util.IMap#size()
996          */
997         public int size() {
998             return this.size;
999         }
1000         
1001     }
1002 
1003     // FIXME - The should ideally be private
1004     /**
1005      * The root node in the tree.
1006      */
1007     transient Node< K, V > root;
1008 
1009     /**
1010      * Constructs a new, emtpy extensible scapegoat tree map.
1011      */
1012     public EBinaryTreeMap() {
1013     }
1014 
1015     /**
1016      * Constructs a new extensible scapegoat tree map which contains all the
1017      * mappings from the specified map.
1018      *
1019      * @param map   the <code>Map</code> to copy mappings from
1020      */
1021     public EBinaryTreeMap( final IMap< K, V > map ) {
1022         if ( map.size() != 0 ) {
1023             final MapIterator< K, V > it = map.iterator( true );
1024             while ( it.hasNext() ) {
1025                 this.insert( it.nextKey(), it.currentValue() );
1026             }
1027         }
1028     }
1029 
1030     /**
1031      * @see java.lang.Object#clone()
1032      */
1033     @Override
1034     @SuppressWarnings( "unchecked" )
1035     public Object clone() throws CloneNotSupportedException {
1036         final EBinaryTreeMap< K, V > map = (EBinaryTreeMap< K, V >) super.clone();
1037         map.root = this.root.deepCopy();
1038         return map;
1039     }
1040 
1041     protected int compare( final K a, final K b ) {
1042         // NOTE - This null handling should ensure that null is pushed as
1043         // far to one side as possible, but doesn't cause an exception
1044         if ( a == null ) {
1045             if ( b == null ) {
1046                 return 0;
1047             } else {
1048                 return Integer.MAX_VALUE;
1049             }
1050         } else {
1051             if ( b == null ) {
1052                 return Integer.MIN_VALUE;
1053             }
1054         }
1055         final Class ca = a.getClass();
1056         final Class cb = b.getClass();
1057         if ( ca == cb ) {
1058             // Ok, a and b are the same type and comparable so use that to
1059             // handle the comparison
1060             return a.compareTo( b );
1061         } else {
1062             // a and b are different types, so use the class names to order
1063             // them. This will result in objects of the same class being
1064             // grouped together, while ordering within a type is handled by
1065             // either the Comparable interface(if implemented) or the types
1066             // hashCode implementation
1067             return ca.getName().compareTo( cb.getName() );
1068         }
1069     }
1070 
1071     /**
1072      * @see org.millscript.commons.util.IMap#contains(java.lang.Object, java.lang.Object)
1073      */
1074     public boolean contains( final K key, final V value ) {
1075         if ( this.root != null ) {
1076             Node< K, V > current = this.root;
1077             while ( current != null ) {
1078                 final int comp = this.compare( key, current.key );
1079                 if ( comp == 0 ) {
1080                     // This node matches
1081                     return value == null ? current.value == null
1082                                          : value.equals( current.value );
1083                 } else if ( comp < 0 ) {
1084                     // We need to search down the left branch
1085                     current = current.left;
1086                 } else {
1087                     // We need to search down the right branch
1088                     current = current.right;
1089                 }
1090             }
1091         }
1092         return false;
1093     }
1094 
1095     /**
1096      * @see org.millscript.commons.util.IMap#containsKey(java.lang.Object)
1097      */
1098     public boolean containsKey( final K key ) {
1099         if ( this.root != null ) {
1100             Node< K, V > current = this.root;
1101             while ( current != null ) {
1102                 final int comp = this.compare( key, current.key );
1103                 if ( comp == 0 ) {
1104                     // This node matches
1105                     return true;
1106                 } else if ( comp < 0 ) {
1107                     // We need to search down the left branch
1108                     current = current.left;
1109                 } else {
1110                     // We need to search down the right branch
1111                     current = current.right;
1112                 }
1113             }
1114         }
1115         return false;
1116     }
1117 
1118     /**
1119      * @see org.millscript.commons.util.IMap#containsValue(java.lang.Object)
1120      */
1121     public boolean containsValue( final V value ) {
1122         if ( this.root != null ) {
1123             Node< K, V > current = this.root.getLeftmost();
1124             while ( current != null ) {
1125                 if ( value == null ? current.value == null : value.equals( current.value ) ) {
1126                     return true;
1127                 } else {
1128                     current = current.getNextInSequence();
1129                 }
1130             }
1131         }
1132         return false;
1133     }
1134 
1135     /**
1136      * @see org.millscript.commons.util.IMap#get(java.lang.Object)
1137      */
1138     public V get( final K key ) {
1139         if ( this.root != null ) {
1140             Node< K, V > current = this.root;
1141             while ( current != null ) {
1142                 final int comp = this.compare( key, current.key );
1143                 if ( comp == 0 ) {
1144                     // This node matches
1145                     return current.value;
1146                 } else if ( comp < 0 ) {
1147                     // We need to search down the left branch
1148                     current = current.left;
1149                 } else {
1150                     // We need to search down the right branch
1151                     current = current.right;
1152                 }
1153             }
1154         }
1155         return this.getDefault().get( this, key );
1156     }
1157 
1158     /**
1159      * @see org.millscript.commons.util.EMap#insert(java.lang.Object, java.lang.Object)
1160      */
1161     public void insert( final K key, final V value ) {
1162         if ( this.root == null ) {
1163             this.root = new Node< K, V >( null, key, value );
1164         } else {
1165             Node< K, V > current = this.root;
1166             while ( current != null ) {
1167                 final int comp = this.compare( key, current.key );
1168                 if ( comp == 0 ) {
1169                     // This node matches, the insert is handled as a fancy update
1170                     // NOTE - We don't need to do any post-processing on the tree
1171                     // as it hasn't changed.
1172                     current.value = value;
1173                     break;
1174                 } else if ( comp < 0 ) {
1175                     // We need to search down the left branch
1176                     if ( current.left == null ) {
1177                         // Add the new node, handling any required tree adjustments
1178                         // resulting from adding the new node
1179                         if ( current.parent == null ) {
1180                             // In general no tree adjustments should be required
1181                             // when inserting an element at the root, so just add
1182                             // the new node
1183                             current.left = new Node< K, V >( current, key, value );
1184                         } else if ( current == current.parent.left && current.parent.right == null ) {
1185                             // This node is the left child of its parent and it has
1186                             // no uncle, add the new node and rotate the tree right
1187                             // about our parent
1188                             current.left = new Node< K, V >( current, key, value );
1189                             current.parent.rotateRight( this );
1190                         } else if ( current == current.parent.right && current.parent.left == null ) {
1191                             // The node is the right child of its parent and it has
1192                             // no uncle. Reorganise the tree putting the new node
1193                             // in place of our parent
1194                             current.parent.insertPushLeft( this, key, value );
1195                         } else {
1196                             // Just add the new node
1197                             current.left = new Node< K, V >( current, key, value );
1198                         }
1199                         break;
1200                     } else {
1201                         current = current.left;
1202                     }
1203                 } else {
1204                     // We need to search down the right branch
1205                     if ( current.right == null ) {
1206                         // Add the new node, handling any required tree adjustments
1207                         // resulting from adding the new node
1208                         if ( current.parent == null ) {
1209                             // In general no tree adjustments should be required
1210                             // when inserting an element at the root, so just add
1211                             // the new node
1212                             current.right = new Node< K, V >( current, key, value );
1213                         } else if ( current == current.parent.right && current.parent.left == null ) {
1214                             // This node is the right child of its parent and it has
1215                             // no uncle, add the new node and rotate the tree left
1216                             // about our parent
1217                             current.right = new Node< K, V >( current, key, value );
1218                             current.parent.rotateLeft( this );
1219                         } else if ( current == current.parent.left && current.parent.right == null ) {
1220                             // The node is the left child of its parent and it has
1221                             // no uncle. Reorganise the tree putting the new node
1222                             // in place of our parent
1223                             current.parent.insertPushRight( this, key, value );
1224                         } else {
1225                             // Just add the new node
1226                             current.right = new Node< K, V >( current, key, value );
1227                         }
1228                         break;
1229                     } else {
1230                         current = current.right;
1231                     }
1232                 }
1233             }
1234             // Update the node size from the current up to the root
1235             while ( current != null ) {
1236                 current.updateSize();
1237                 current = current.parent;
1238             }
1239         }
1240     }
1241 
1242     /**
1243      * @see org.millscript.commons.util.IMap#iterator(boolean)
1244      */
1245     public MapIterator< K, V > iterator( final boolean share ) {
1246         return new NodeIterator< K, V >( this.root, share );
1247     }
1248 
1249     /**
1250      * Reads this object from the specified {@link ObjectInputStream}.
1251      *
1252      * @param stream    the {@link ObjectInputStream} to read the objects data
1253      * from
1254      * @serialData      Reads the default object, followed by the integer
1255      * number of mappings and then an alternating sequence of key-value pairs
1256      * @throws ClassNotFoundException   if a required class cannot be found
1257      * @throws IOException      if something goes wrong during the
1258      * deserialization process
1259      */
1260     @SuppressWarnings( "unchecked" )
1261     private void readObject( final ObjectInputStream stream ) throws ClassNotFoundException, IOException {
1262         // Write the default stuff
1263         stream.defaultReadObject();
1264         // Retrieve the number of mappings in the array.
1265         final int size = stream.readInt();
1266         // Allocate arrays to temporarily store the mappings in
1267         final K[] keys = (K[]) new Comparable[ size ];
1268         final V[] values = (V[]) new Comparable[ size ];
1269         for ( int i = 0; i < size; i++ ) {
1270             keys[ i ] = (K) stream.readObject();
1271             values[ i ] = (V) stream.readObject();
1272         }
1273         this.root = new Node< K, V >( null, keys, values, 1, size );
1274     }
1275 
1276     /**
1277      * @see org.millscript.commons.util.EMap#remove(java.lang.Object, java.lang.Object)
1278      */
1279     public void remove( final K key, final V value ) {
1280         if ( this.root != null ) {
1281             Node< K, V > current = this.root;
1282             Node< K, V > parent = null;
1283             while ( current != null ) {
1284                 final int comp = this.compare( key, current.key );
1285                 if ( comp == 0 ) {
1286                     // This node matches, check the value to see if it matches the
1287                     // supplied one.
1288                     if ( value == null ? current.value == null : value.equals( current.value ) ) {
1289                         // Ok, the node matches completely, delete!
1290                         current = current.remove( this );
1291                         break;
1292                     }
1293                 } else if ( comp < 0 ) {
1294                     // We need to search down the left branch
1295                     parent = current;
1296                     current = current.left;
1297                 } else {
1298                     // We need to search down the right branch
1299                     parent = current;
1300                     current = current.right;
1301                 }
1302             }
1303             // Update the node size from the current up to the root
1304             while ( parent != null ) {
1305                 parent.updateSize();
1306                 parent = parent.parent;
1307             }
1308         }
1309     }
1310 
1311     /**
1312      * @see org.millscript.commons.util.EMap#removeAll()
1313      */
1314     public void removeAll() {
1315         this.root = null;
1316     }
1317 
1318     /**
1319      * @see org.millscript.commons.util.EMap#removeKey(java.lang.Object)
1320      */
1321     public void removeKey( final K key ) {
1322         if ( this.root != null ) {
1323             Node< K, V > current = this.root;
1324             while ( current != null ) {
1325                 final int comp = this.compare( key, current.key );
1326                 if ( comp == 0 ) {
1327                     // This node matches
1328                     current = current.remove( this );
1329                     break;
1330                 } else if ( comp < 0 ) {
1331                     // We need to search down the left branch
1332                     current = current.left;
1333                 } else {
1334                     // We need to search down the right branch
1335                     current = current.right;
1336                 }
1337             }
1338             // Update the node size from the current up to the root
1339             while ( current != null ) {
1340                 current.updateSize();
1341                 current = current.parent;
1342             }
1343         }
1344     }
1345 
1346     /**
1347      * @see org.millscript.commons.util.EMap#removeValue(java.lang.Object)
1348      */
1349     public void removeValue( final V value ) {
1350         if ( this.root != null ) {
1351             Node< K, V > current = this.root.getLeftmost();
1352             while ( current != null ) {
1353                 if ( value == null ? current.value == null : value.equals( current.value ) ) {
1354                     current = current.remove( this );
1355                     for ( Node fixsize = current; fixsize != null; fixsize = fixsize.parent ) {
1356                         fixsize.updateSize();
1357                     }
1358                 } else {
1359                     current = current.getNextInSequence();
1360                 }
1361             }
1362         }
1363     }
1364 
1365     /**
1366      * @see org.millscript.commons.util.map.AbstractIMap#sharedKeyList()
1367      */
1368     @Override
1369     protected IList< K > sharedKeyList() {
1370         return new NodeKeyList< K >( this.root, 1, this.size() );
1371     }
1372 
1373     /**
1374      * @see org.millscript.commons.util.map.AbstractIMap#sharedMapletList()
1375      */
1376     @Override
1377     protected IList< Maplet< K, V > > sharedMapletList() {
1378         return new NodeMapletList< K, V >( this.root, 1, this.size() );
1379     }
1380 
1381     /**
1382      * @see org.millscript.commons.util.map.AbstractIMap#sharedValueList()
1383      */
1384     @Override
1385     protected IList< V > sharedValueList() {
1386         return new NodeValueList< V >( this.root, 1, this.size() );
1387     }
1388 
1389     /**
1390      * @see org.millscript.commons.util.IMap#size()
1391      */
1392     public int size() {
1393         return this.root == null ? 0 : this.root.size;
1394     }
1395 
1396     /**
1397      * @see org.millscript.commons.util.UMap#update(java.lang.Object, java.lang.Object)
1398      */
1399     public void update( final K key, final V value ) {
1400         if ( this.root != null ) {
1401             Node< K, V > current = this.root;
1402             while ( current != null ) {
1403                 final int comp = this.compare( key, current.key );
1404                 if ( comp == 0 ) {
1405                     // This node matches
1406                     current.value = value;
1407                     return;
1408                 } else if ( comp < 0 ) {
1409                     // We need to search down the left branch
1410                     current = current.left;
1411                 } else {
1412                     // We need to search down the right branch
1413                     current = current.right;
1414                 }
1415             }
1416         }
1417         throw new NoSuchKeyInMapAlert(
1418             "Only pre-existing keys can have their values updated"
1419         ).culpritKey( key ).decorate( this ).mishap();
1420     }
1421 
1422     /**
1423      * Writes this object to the specified {@link ObjectOutputStream}.
1424      *
1425      * @param stream    the {@link ObjectOutputStream} to write this object to
1426      * @serialData      Writes the default object and then an alternating
1427      * sequence of key-value pairs
1428      * @throws IOException      if something goes wrong during the
1429      * serialization process
1430      */
1431     private void writeObject( final ObjectOutputStream stream ) throws IOException {
1432         // Write the default stuff
1433         stream.defaultWriteObject();
1434         // Save the number of mappings in the array.