1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the  "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: NodeVector.java 468655 2006-10-28 07:12:06Z minchau $
20 */
21package org.apache.xml.utils;
22
23import java.io.Serializable;
24
25import org.apache.xml.dtm.DTM;
26
27/**
28 * A very simple table that stores a list of Nodes.
29 * @xsl.usage internal
30 */
31public class NodeVector implements Serializable, Cloneable
32{
33    static final long serialVersionUID = -713473092200731870L;
34
35  /**
36   * Size of blocks to allocate.
37   *  @serial
38   */
39  private int m_blocksize;
40
41  /**
42   * Array of nodes this points to.
43   *  @serial
44   */
45  private int m_map[];
46
47  /**
48   * Number of nodes in this NodeVector.
49   *  @serial
50   */
51  protected int m_firstFree = 0;
52
53  /**
54   * Size of the array this points to.
55   *  @serial
56   */
57  private int m_mapSize;  // lazy initialization
58
59  /**
60   * Default constructor.
61   */
62  public NodeVector()
63  {
64    m_blocksize = 32;
65    m_mapSize = 0;
66  }
67
68  /**
69   * Construct a NodeVector, using the given block size.
70   *
71   * @param blocksize Size of blocks to allocate
72   */
73  public NodeVector(int blocksize)
74  {
75    m_blocksize = blocksize;
76    m_mapSize = 0;
77  }
78
79  /**
80   * Get a cloned LocPathIterator.
81   *
82   * @return A clone of this
83   *
84   * @throws CloneNotSupportedException
85   */
86  public Object clone() throws CloneNotSupportedException
87  {
88
89    NodeVector clone = (NodeVector) super.clone();
90
91    if ((null != this.m_map) && (this.m_map == clone.m_map))
92    {
93      clone.m_map = new int[this.m_map.length];
94
95      System.arraycopy(this.m_map, 0, clone.m_map, 0, this.m_map.length);
96    }
97
98    return clone;
99  }
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 pivot = a[(lo + hi) / 2];
672
673    a[(lo + hi) / 2] = a[hi];
674    a[hi] = pivot;
675
676    while (lo < hi)
677    {
678
679      /*
680       *  Search forward from a[lo] until an element is found that
681       *  is greater than the pivot or lo >= hi
682       */
683      while (a[lo] <= pivot && lo < hi)
684      {
685        lo++;
686      }
687
688      /*
689       *  Search backward from a[hi] until element is found that
690       *  is less than the pivot, or lo >= hi
691       */
692      while (pivot <= a[hi] && lo < hi)
693      {
694        hi--;
695      }
696
697      /*
698       *  Swap elements a[lo] and a[hi]
699       */
700      if (lo < hi)
701      {
702        int T = a[lo];
703
704        a[lo] = a[hi];
705        a[hi] = T;
706
707        // pause();
708      }
709
710      // if (stopRequested) {
711      //    return;
712      // }
713    }
714
715    /*
716     *  Put the median in the "center" of the list
717     */
718    a[hi0] = a[hi];
719    a[hi] = pivot;
720
721    /*
722     *  Recursive calls, elements a[lo0] to a[lo-1] are less than or
723     *  equal to pivot, elements a[hi+1] to a[hi0] are greater than
724     *  pivot.
725     */
726    sort(a, lo0, lo - 1);
727    sort(a, hi + 1, hi0);
728  }
729
730  /**
731   * Sort an array using a quicksort algorithm.
732   *
733   * @throws Exception
734   */
735  public void sort() throws Exception
736  {
737    sort(m_map, 0, m_firstFree - 1);
738  }
739}
740