001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: NodeVector.java 1225445 2011-12-29 06:08:53Z mrglavas $
020     */
021    package org.apache.xml.utils;
022    
023    import java.io.Serializable;
024    
025    import org.apache.xml.dtm.DTM;
026    
027    /**
028     * A very simple table that stores a list of Nodes.
029     * @xsl.usage internal
030     */
031    public class NodeVector implements Serializable, Cloneable
032    {
033        static final long serialVersionUID = -713473092200731870L;
034    
035      /**
036       * Size of blocks to allocate.
037       *  @serial          
038       */
039      private int m_blocksize;
040    
041      /**
042       * Array of nodes this points to.
043       *  @serial          
044       */
045      private int m_map[];
046    
047      /**
048       * Number of nodes in this NodeVector.
049       *  @serial          
050       */
051      protected int m_firstFree = 0;
052    
053      /**
054       * Size of the array this points to.
055       *  @serial           
056       */
057      private int m_mapSize;  // lazy initialization
058    
059      /**
060       * Default constructor.
061       */
062      public NodeVector()
063      {
064        m_blocksize = 32;
065        m_mapSize = 0;
066      }
067    
068      /**
069       * Construct a NodeVector, using the given block size.
070       *
071       * @param blocksize Size of blocks to allocate
072       */
073      public NodeVector(int blocksize)
074      {
075        m_blocksize = blocksize;
076        m_mapSize = 0;
077      }
078    
079      /**
080       * Get a cloned LocPathIterator.
081       *
082       * @return A clone of this
083       *
084       * @throws CloneNotSupportedException
085       */
086      public Object clone() throws CloneNotSupportedException
087      {
088    
089        NodeVector clone = (NodeVector) super.clone();
090    
091        if ((null != this.m_map) && (this.m_map == clone.m_map))
092        {
093          clone.m_map = new int[this.m_map.length];
094    
095          System.arraycopy(this.m_map, 0, clone.m_map, 0, this.m_map.length);
096        }
097    
098        return clone;
099      }
100    
101      /**
102       * Get the length of the list.
103       *
104       * @return Number of nodes in this NodeVector
105       */
106      public int size()
107      {
108        return m_firstFree;
109      }
110    
111      /**
112       * Append a Node onto the vector.
113       *
114       * @param value Node to add to the vector
115       */
116      public void addElement(int value)
117      {
118    
119        if ((m_firstFree + 1) >= m_mapSize)
120        {
121          if (null == m_map)
122          {
123            m_map = new int[m_blocksize];
124            m_mapSize = m_blocksize;
125          }
126          else
127          {
128            m_mapSize += m_blocksize;
129    
130            int newMap[] = new int[m_mapSize];
131    
132            System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1);
133    
134            m_map = newMap;
135          }
136        }
137    
138        m_map[m_firstFree] = value;
139    
140        m_firstFree++;
141      }
142    
143      /**
144       * Append a Node onto the vector.
145       *
146       * @param value Node to add to the vector
147       */
148      public final void push(int value)
149      {
150    
151        int ff = m_firstFree;
152    
153        if ((ff + 1) >= m_mapSize)
154        {
155          if (null == m_map)
156          {
157            m_map = new int[m_blocksize];
158            m_mapSize = m_blocksize;
159          }
160          else
161          {
162            m_mapSize += m_blocksize;
163    
164            int newMap[] = new int[m_mapSize];
165    
166            System.arraycopy(m_map, 0, newMap, 0, ff + 1);
167    
168            m_map = newMap;
169          }
170        }
171    
172        m_map[ff] = value;
173    
174        ff++;
175    
176        m_firstFree = ff;
177      }
178    
179      /**
180       * Pop a node from the tail of the vector and return the result.
181       *
182       * @return the node at the tail of the vector
183       */
184      public final int pop()
185      {
186    
187        m_firstFree--;
188    
189        int n = m_map[m_firstFree];
190    
191        m_map[m_firstFree] = DTM.NULL;
192    
193        return n;
194      }
195    
196      /**
197       * Pop a node from the tail of the vector and return the
198       * top of the stack after the pop.
199       *
200       * @return The top of the stack after it's been popped
201       */
202      public final int popAndTop()
203      {
204    
205        m_firstFree--;
206    
207        m_map[m_firstFree] = DTM.NULL;
208    
209        return (m_firstFree == 0) ? DTM.NULL : m_map[m_firstFree - 1];
210      }
211    
212      /**
213       * Pop a node from the tail of the vector.
214       */
215      public final void popQuick()
216      {
217    
218        m_firstFree--;
219    
220        m_map[m_firstFree] = DTM.NULL;
221      }
222    
223      /**
224       * Return the node at the top of the stack without popping the stack.
225       * Special purpose method for TransformerImpl, pushElemTemplateElement.
226       * Performance critical.
227       *
228       * @return Node at the top of the stack or null if stack is empty.
229       */
230      public final int peepOrNull()
231      {
232        return ((null != m_map) && (m_firstFree > 0))
233               ? m_map[m_firstFree - 1] : DTM.NULL;
234      }
235    
236      /**
237       * Push a pair of nodes into the stack.
238       * Special purpose method for TransformerImpl, pushElemTemplateElement.
239       * Performance critical.
240       *
241       * @param v1 First node to add to vector
242       * @param v2 Second node to add to vector
243       */
244      public final void pushPair(int v1, int v2)
245      {
246    
247        if (null == m_map)
248        {
249          m_map = new int[m_blocksize];
250          m_mapSize = m_blocksize;
251        }
252        else
253        {
254          if ((m_firstFree + 2) >= m_mapSize)
255          {
256            m_mapSize += m_blocksize;
257    
258            int newMap[] = new int[m_mapSize];
259    
260            System.arraycopy(m_map, 0, newMap, 0, m_firstFree);
261    
262            m_map = newMap;
263          }
264        }
265    
266        m_map[m_firstFree] = v1;
267        m_map[m_firstFree + 1] = v2;
268        m_firstFree += 2;
269      }
270    
271      /**
272       * Pop a pair of nodes from the tail of the stack.
273       * Special purpose method for TransformerImpl, pushElemTemplateElement.
274       * Performance critical.
275       */
276      public final void popPair()
277      {
278    
279        m_firstFree -= 2;
280        m_map[m_firstFree] = DTM.NULL;
281        m_map[m_firstFree + 1] = DTM.NULL;
282      }
283    
284      /**
285       * Set the tail of the stack to the given node.
286       * Special purpose method for TransformerImpl, pushElemTemplateElement.
287       * Performance critical.
288       *
289       * @param n Node to set at the tail of vector
290       */
291      public final void setTail(int n)
292      {
293        m_map[m_firstFree - 1] = n;
294      }
295    
296      /**
297       * Set the given node one position from the tail.
298       * Special purpose method for TransformerImpl, pushElemTemplateElement.
299       * Performance critical.
300       *
301       * @param n Node to set
302       */
303      public final void setTailSub1(int n)
304      {
305        m_map[m_firstFree - 2] = n;
306      }
307    
308      /**
309       * Return the node at the tail of the vector without popping
310       * Special purpose method for TransformerImpl, pushElemTemplateElement.
311       * Performance critical.
312       *
313       * @return Node at the tail of the vector
314       */
315      public final int peepTail()
316      {
317        return m_map[m_firstFree - 1];
318      }
319    
320      /**
321       * Return the node one position from the tail without popping.
322       * Special purpose method for TransformerImpl, pushElemTemplateElement.
323       * Performance critical.
324       *
325       * @return Node one away from the tail
326       */
327      public final int peepTailSub1()
328      {
329        return m_map[m_firstFree - 2];
330      }
331    
332      /**
333       * Insert a node in order in the list.
334       *
335       * @param value Node to insert
336       */
337      public void insertInOrder(int value)
338      {
339    
340        for (int i = 0; i < m_firstFree; i++)
341        {
342          if (value < m_map[i])
343          {
344            insertElementAt(value, i);
345    
346            return;
347          }
348        }
349    
350        addElement(value);
351      }
352    
353      /**
354       * Inserts the specified node in this vector at the specified index.
355       * Each component in this vector with an index greater or equal to
356       * the specified index is shifted upward to have an index one greater
357       * than the value it had previously.
358       *
359       * @param value Node to insert
360       * @param at Position where to insert
361       */
362      public void insertElementAt(int value, int at)
363      {
364    
365        if (null == m_map)
366        {
367          m_map = new int[m_blocksize];
368          m_mapSize = m_blocksize;
369        }
370        else if ((m_firstFree + 1) >= m_mapSize)
371        {
372          m_mapSize += m_blocksize;
373    
374          int newMap[] = new int[m_mapSize];
375    
376          System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1);
377    
378          m_map = newMap;
379        }
380    
381        if (at <= (m_firstFree - 1))
382        {
383          System.arraycopy(m_map, at, m_map, at + 1, m_firstFree - at);
384        }
385    
386        m_map[at] = value;
387    
388        m_firstFree++;
389      }
390    
391      /**
392       * Append the nodes to the list.
393       *
394       * @param nodes NodeVector to append to this list
395       */
396      public void appendNodes(NodeVector nodes)
397      {
398    
399        int nNodes = nodes.size();
400    
401        if (null == m_map)
402        {
403          m_mapSize = nNodes + m_blocksize;
404          m_map = new int[m_mapSize];
405        }
406        else if ((m_firstFree + nNodes) >= m_mapSize)
407        {
408          m_mapSize += (nNodes + m_blocksize);
409    
410          int newMap[] = new int[m_mapSize];
411    
412          System.arraycopy(m_map, 0, newMap, 0, m_firstFree + nNodes);
413    
414          m_map = newMap;
415        }
416    
417        System.arraycopy(nodes.m_map, 0, m_map, m_firstFree, nNodes);
418    
419        m_firstFree += nNodes;
420      }
421    
422      /**
423       * Inserts the specified node in this vector at the specified index.
424       * Each component in this vector with an index greater or equal to
425       * the specified index is shifted upward to have an index one greater
426       * than the value it had previously.
427       */
428      public void removeAllElements()
429      {
430    
431        if (null == m_map)
432          return;
433    
434        for (int i = 0; i < m_firstFree; i++)
435        {
436          m_map[i] = DTM.NULL;
437        }
438    
439        m_firstFree = 0;
440      }
441      
442      /**
443       * Set the length to zero, but don't clear the array.
444       */
445      public void RemoveAllNoClear()
446      {
447    
448        if (null == m_map)
449          return;
450    
451        m_firstFree = 0;
452      }
453    
454      /**
455       * Removes the first occurrence of the argument from this vector.
456       * If the object is found in this vector, each component in the vector
457       * with an index greater or equal to the object's index is shifted
458       * downward to have an index one smaller than the value it had
459       * previously.
460       *
461       * @param s Node to remove from the list
462       *
463       * @return True if the node was successfully removed
464       */
465      public boolean removeElement(int s)
466      {
467    
468        if (null == m_map)
469          return false;
470    
471        for (int i = 0; i < m_firstFree; i++)
472        {
473          int node = m_map[i];
474    
475          if (node == s)
476          {
477            if (i > m_firstFree)
478              System.arraycopy(m_map, i + 1, m_map, i - 1, m_firstFree - i);
479            else
480              m_map[i] = DTM.NULL;
481    
482            m_firstFree--;
483    
484            return true;
485          }
486        }
487    
488        return false;
489      }
490    
491      /**
492       * Deletes the component at the specified index. Each component in
493       * this vector with an index greater or equal to the specified
494       * index is shifted downward to have an index one smaller than
495       * the value it had previously.
496       *
497       * @param i Index of node to remove
498       */
499      public void removeElementAt(int i)
500      {
501    
502        if (null == m_map)
503          return;
504    
505        if (i > m_firstFree)
506          System.arraycopy(m_map, i + 1, m_map, i - 1, m_firstFree - i);
507        else
508          m_map[i] = DTM.NULL;
509      }
510    
511      /**
512       * Sets the component at the specified index of this vector to be the
513       * specified object. The previous component at that position is discarded.
514       *
515       * The index must be a value greater than or equal to 0 and less
516       * than the current size of the vector.
517       *
518       * @param node Node to set
519       * @param index Index of where to set the node
520       */
521      public void setElementAt(int node, int index)
522      {
523    
524        if (null == m_map)
525        {
526          m_map = new int[m_blocksize];
527          m_mapSize = m_blocksize;
528        }
529        
530        if(index == -1)
531            addElement(node);
532    
533        m_map[index] = node;
534      }
535    
536      /**
537       * Get the nth element.
538       *
539       * @param i Index of node to get
540       *
541       * @return Node at specified index
542       */
543      public int elementAt(int i)
544      {
545    
546        if (null == m_map)
547          return DTM.NULL;
548    
549        return m_map[i];
550      }
551    
552      /**
553       * Tell if the table contains the given node.
554       *
555       * @param s Node to look for
556       *
557       * @return True if the given node was found.
558       */
559      public boolean contains(int s)
560      {
561    
562        if (null == m_map)
563          return false;
564    
565        for (int i = 0; i < m_firstFree; i++)
566        {
567          int node = m_map[i];
568    
569          if (node == s)
570            return true;
571        }
572    
573        return false;
574      }
575    
576      /**
577       * Searches for the first occurence of the given argument,
578       * beginning the search at index, and testing for equality
579       * using the equals method.
580       *
581       * @param elem Node to look for
582       * @param index Index of where to start the search
583       * @return the index of the first occurrence of the object
584       * argument in this vector at position index or later in the
585       * vector; returns -1 if the object is not found.
586       */
587      public int indexOf(int elem, int index)
588      {
589    
590        if (null == m_map)
591          return -1;
592    
593        for (int i = index; i < m_firstFree; i++)
594        {
595          int node = m_map[i];
596    
597          if (node == elem)
598            return i;
599        }
600    
601        return -1;
602      }
603    
604      /**
605       * Searches for the first occurence of the given argument,
606       * beginning the search at index, and testing for equality
607       * using the equals method.
608       *
609       * @param elem Node to look for
610       * @return the index of the first occurrence of the object
611       * argument in this vector at position index or later in the
612       * vector; returns -1 if the object is not found.
613       */
614      public int indexOf(int elem)
615      {
616    
617        if (null == m_map)
618          return -1;
619    
620        for (int i = 0; i < m_firstFree; i++)
621        {
622          int node = m_map[i];
623    
624          if (node == elem)
625            return i;
626        }
627    
628        return -1;
629      }
630    
631      /**
632       * Sort an array using a quicksort algorithm.
633       *
634       * @param a The array to be sorted.
635       * @param lo0  The low index.
636       * @param hi0  The high index.
637       *
638       * @throws Exception
639       */
640      public void sort(int a[], int lo0, int hi0) throws Exception
641      {
642    
643        int lo = lo0;
644        int hi = hi0;
645    
646        // pause(lo, hi);
647        if (lo >= hi)
648        {
649          return;
650        }
651        else if (lo == hi - 1)
652        {
653    
654          /*
655           *  sort a two element list by swapping if necessary
656           */
657          if (a[lo] > a[hi])
658          {
659            int T = a[lo];
660    
661            a[lo] = a[hi];
662            a[hi] = T;
663          }
664    
665          return;
666        }
667    
668        /*
669         *  Pick a pivot and move it out of the way
670         */
671        int mid = (lo + hi) >>> 1;
672        int pivot = a[mid];
673    
674        a[mid] = a[hi];
675        a[hi] = pivot;
676    
677        while (lo < hi)
678        {
679    
680          /*
681           *  Search forward from a[lo] until an element is found that
682           *  is greater than the pivot or lo >= hi
683           */
684          while (a[lo] <= pivot && lo < hi)
685          {
686            lo++;
687          }
688    
689          /*
690           *  Search backward from a[hi] until element is found that
691           *  is less than the pivot, or lo >= hi
692           */
693          while (pivot <= a[hi] && lo < hi)
694          {
695            hi--;
696          }
697    
698          /*
699           *  Swap elements a[lo] and a[hi]
700           */
701          if (lo < hi)
702          {
703            int T = a[lo];
704    
705            a[lo] = a[hi];
706            a[hi] = T;
707    
708            // pause();
709          }
710    
711          // if (stopRequested) {
712          //    return;
713          // }
714        }
715    
716        /*
717         *  Put the median in the "center" of the list
718         */
719        a[hi0] = a[hi];
720        a[hi] = pivot;
721    
722        /*
723         *  Recursive calls, elements a[lo0] to a[lo-1] are less than or
724         *  equal to pivot, elements a[hi+1] to a[hi0] are greater than
725         *  pivot.
726         */
727        sort(a, lo0, lo - 1);
728        sort(a, hi + 1, hi0);
729      }
730    
731      /**
732       * Sort an array using a quicksort algorithm.
733       *
734       * @throws Exception
735       */
736      public void sort() throws Exception
737      {
738        sort(m_map, 0, m_firstFree - 1);
739      }
740    }