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: SortingIterator.java 468651 2006-10-28 07:04:25Z minchau $
020     */
021    
022    package org.apache.xalan.xsltc.dom;
023    
024    import org.apache.xalan.xsltc.runtime.BasisLibrary;
025    import org.apache.xml.dtm.DTMAxisIterator;
026    import org.apache.xml.dtm.ref.DTMAxisIteratorBase;
027    
028    /**
029     * @author Jacek Ambroziak
030     * @author Santiago Pericas-Geertsen
031     * @author Morten Jorgensen
032     */
033    public final class SortingIterator extends DTMAxisIteratorBase {
034        private final static int INIT_DATA_SIZE = 16;
035    
036        private DTMAxisIterator _source;
037        private NodeSortRecordFactory _factory;
038    
039        private NodeSortRecord[] _data;
040        private int _free = 0;
041        private int _current;       // index in _nodes of the next node to try
042    
043        public SortingIterator(DTMAxisIterator source, 
044                               NodeSortRecordFactory factory) {
045            _source = source;
046            _factory = factory;
047        }
048    
049        public int next() {
050            return _current < _free ? _data[_current++].getNode() : END;
051        }
052            
053        public DTMAxisIterator setStartNode(int node) {
054            try {
055                _source.setStartNode(_startNode = node);
056                _data = new NodeSortRecord[INIT_DATA_SIZE];
057                _free = 0;
058    
059                // gather all nodes from the source iterator
060                while ((node = _source.next()) != END) {
061                    addRecord(_factory.makeNodeSortRecord(node,_free));
062                }
063                // now sort the records
064                quicksort(0, _free - 1);
065    
066                _current = 0;
067                return this;
068            }
069            catch (Exception e) {
070                return this;
071            }
072        }
073            
074        public int getPosition() {
075            return _current == 0 ? 1 : _current;
076        }
077    
078        public int getLast() {
079            return _free;
080        }
081    
082        public void setMark() {
083            _source.setMark();
084            _markedNode = _current;
085        }
086    
087        public void gotoMark() {
088            _source.gotoMark();
089            _current = _markedNode;
090        }
091        
092        /**
093         * Clone a <code>SortingIterator</code> by cloning its source
094         * iterator and then sharing the factory and the array of
095         * <code>NodeSortRecords</code>.
096         */
097        public DTMAxisIterator cloneIterator() {
098            try {
099                final SortingIterator clone = (SortingIterator) super.clone();
100                clone._source = _source.cloneIterator();  
101                clone._factory = _factory;          // shared between clones
102                clone._data = _data;                // shared between clones
103                clone._free = _free;
104                clone._current = _current;
105                clone.setRestartable(false);
106                return clone.reset();
107            }
108            catch (CloneNotSupportedException e) {
109                BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
110                                          e.toString());
111                return null;
112            }
113        }
114    
115        private void addRecord(NodeSortRecord record) {
116            if (_free == _data.length) {
117                NodeSortRecord[] newArray = new NodeSortRecord[_data.length * 2];
118                System.arraycopy(_data, 0, newArray, 0, _free);
119                _data = newArray;
120            }
121            _data[_free++] = record;
122        }
123    
124        private void quicksort(int p, int r) {
125            while (p < r) {
126                final int q = partition(p, r);
127                quicksort(p, q);
128                p = q + 1;
129            }
130        }
131        
132        private int partition(int p, int r) {
133            final NodeSortRecord x = _data[(p + r) >>> 1];
134            int i = p - 1;
135            int j = r + 1;
136            while (true) {
137                while (x.compareTo(_data[--j]) < 0);
138                while (x.compareTo(_data[++i]) > 0);
139                if (i < j) {
140                    final NodeSortRecord t = _data[i];
141                    _data[i] = _data[j];
142                    _data[j] = t;
143                }
144                else {
145                    return(j);
146                }
147            }
148        }
149    }