mmidy 00/02/04 12:41:51
Modified: src/org/apache/xalan/xslt NodeSorter.java
Log:
Changes to improve performance of xsl:sort
Revision Changes Path
1.6 +154 -27 xml-xalan/src/org/apache/xalan/xslt/NodeSorter.java
Index: NodeSorter.java
===================================================================
RCS file: /home/cvs/xml-xalan/src/org/apache/xalan/xslt/NodeSorter.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- NodeSorter.java 2000/01/31 20:52:31 1.5
+++ NodeSorter.java 2000/02/04 20:41:51 1.6
@@ -76,7 +76,7 @@
/**
* TODO: Adjust this for locale.
*/
- NumberFormat m_formatter = NumberFormat.getNumberInstance();
+ NumberFormat m_formatter = NumberFormat.getNumberInstance();
/**
* Construct a NodeSorter, passing in the XSL Processor
@@ -103,30 +103,70 @@
m_keys = keys;
// QuickSort2(v, 0, v.size() - 1 );
int n = v.size();
- NodeVector scratchVector = new NodeVector(n);
- mergesort(v, scratchVector, 0, n - 1, support);
+
+ // Create a vector of node compare elements
+ // based on the input vector of nodes
+ Vector nodes = new Vector();
+ for (int i = 0; i<n; i++)
+ {
+ NodeCompareElem elem = new NodeCompareElem((Node)v.elementAt(i));
+ nodes.addElement(elem);
+ }
+ Vector scratchVector = new Vector();
+ mergesort(nodes, scratchVector, 0, n - 1, support);
+
+ // return sorted vector of nodes
+ for (int i = 0; i<n; i++)
+ {
+ v.setElementAt(((NodeCompareElem)nodes.elementAt(i)).m_node, i);
+ }
+ // old code...
+ //NodeVector scratchVector = new NodeVector(n);
+ //mergesort(v, scratchVector, 0, n - 1, support);
}
/**
* Return the results of a compare of two nodes.
* TODO: Optimize compare -- cache the getStringExpr results, key by
m_selectPat + hash of node.
*/
- int compare(Node n1, Node n2, int kIndex, XPathSupport support)
+ int compare(NodeCompareElem n1, NodeCompareElem n2, int kIndex,
XPathSupport support)
throws org.xml.sax.SAXException,
java.net.MalformedURLException,
java.io.FileNotFoundException,
java.io.IOException
{
int result = 0;
- NodeSortKey k = (NodeSortKey)m_keys.elementAt(kIndex);
- XObject r1 = k.m_selectPat.execute(m_execContext, n1,
k.m_namespaceContext);
- XObject r2 = k.m_selectPat.execute(m_execContext, n2,
k.m_namespaceContext);
-
+
+ NodeSortKey k = (NodeSortKey)m_keys.elementAt(kIndex);
if(k.m_treatAsNumbers)
{
- double n1Num = r1.num();
- double n2Num = r2.num();
-
+ double n1Num, n2Num;
+ if (kIndex ==0)
+ {
+ n1Num = ((Double)n1.m_key1Value).doubleValue();
+ n2Num = ((Double)n2.m_key1Value).doubleValue();
+ }
+ else if (kIndex ==1)
+ {
+ n1Num = ((Double)n1.m_key2Value).doubleValue();
+ n2Num = ((Double)n2.m_key2Value).doubleValue();
+ }
+ /* Leave this in case we decide to use an array later
+ if (kIndex < maxkey)
+ {
+ double n1Num = (double)n1.m_keyValue[kIndex];
+ double n2Num = (double)n2.m_keyValue[kIndex];
+ }*/
+ else
+ {
+ // Get values dynamically
+ XObject r1 = k.m_selectPat.execute(m_execContext, n1.m_node,
k.m_namespaceContext);
+ XObject r2 = k.m_selectPat.execute(m_execContext, n2.m_node,
k.m_namespaceContext);
+
+ n1Num = r1.num();
+ n2Num = r2.num();
+ }
+
if((n1Num == n2Num) && ((kIndex+1) < m_keys.size()))
{
result = compare(n1, n2, kIndex+1, support);
@@ -134,24 +174,51 @@
else
{
double diff = n1Num - n2Num;
+ // process order parameter
result = (int)((diff < 0.0)
? (k.m_descending ? 1 : -1)
: (diff > 0.0) ? (k.m_descending ? -1 : 1)
: 0);
}
- }
+ }// end treat as numbers
else
{
- String n1String = r1.str();
- String n2String = r2.str();
-
- result = k.m_col.compare(n1String, n2String);
-
+ CollationKey n1String, n2String;
+ if (kIndex == 0)
+ {
+ n1String = (CollationKey)n1.m_key1Value;
+ n2String = (CollationKey)n2.m_key1Value;
+ }
+ else if (kIndex == 1)
+ {
+ n1String = (CollationKey)n1.m_key2Value;
+ n2String = (CollationKey)n2.m_key2Value;
+ }
+ /* Leave this in case we decide to use an array later
+ if (kIndex < maxkey)
+ {
+ String n1String = (String)n1.m_keyValue[kIndex];
+ String n2String = (String)n2.m_keyValue[kIndex];
+ }*/
+ else
+ {
+ // Get values dynamically
+ XObject r1 = k.m_selectPat.execute(m_execContext, n1.m_node,
k.m_namespaceContext);
+ XObject r2 = k.m_selectPat.execute(m_execContext, n2.m_node,
k.m_namespaceContext);
+
+ n1String = k.m_col.getCollationKey(r1.str());
+ n2String = k.m_col.getCollationKey(r2.str());
+ }
+
+ // Use collation keys for faster compare, but note that whitespaces
+ // etc... are treated differently from if we were comparing Strings.
+ result = n1String.compareTo(n2String);
+
//Process caseOrder parameter
if (k.m_caseOrderUpper)
{
- String tempN1 = n1String.toLowerCase();
- String tempN2 = n2String.toLowerCase();
+ String tempN1 = n1String.getSourceString().toLowerCase();
+ String tempN2 = n2String.getSourceString().toLowerCase();
if (tempN1.equals(tempN2))
{
//java defaults to upper case is greater.
@@ -164,7 +231,8 @@
{
result = -result;
}
- }
+ }//end else
+
if(0 == result)
{
if((kIndex+1) < m_keys.size())
@@ -179,7 +247,7 @@
// if(r1.getType() == r1.CLASS_NODESET)
// {
- result = MutableNodeListImpl.isNodeAfter(n1, n2, support) ? -1 : 1;
+ result = MutableNodeListImpl.isNodeAfter(n1.m_node, n2.m_node,
support) ? -1 : 1;
// }
}
return result;
@@ -192,7 +260,7 @@
* maintains the original document order of the input if
* the order isn't changed by the sort.
*/
- void mergesort(NodeVector a, NodeVector b, int l, int r, XPathSupport
support)
+ void mergesort(Vector a, Vector b, int l, int r, XPathSupport support)
throws org.xml.sax.SAXException,
java.net.MalformedURLException,
java.io.FileNotFoundException,
@@ -207,20 +275,30 @@
for(i = m; i >= l; i--)
{
// b[i] = a[i];
- b.setElementAt(a.elementAt(i), i);
+ // Use insert if we need to increment vector size.
+ if (i >= b.size())
+ b.insertElementAt(a.elementAt(i), i);
+ else
+ b.setElementAt(a.elementAt(i), i);
}
i=l;
for(j = (m + 1); j <= r; j++)
{
// b[r+m+1-j] = a[j];
- b.setElementAt(a.elementAt(j), r+m+1-j);
+ if (r+m+1-j>= b.size())
+ b.insertElementAt(a.elementAt(j), r+m+1-j);
+ else
+ b.setElementAt(a.elementAt(j), r+m+1-j);
}
j=r;
int compVal;
for(k = l; k <= r; k++)
{
// if(b[i] < b[j])
- compVal = compare((Node)b.elementAt(i), (Node)b.elementAt(j), 0,
support);
+ if (i == j)
+ compVal = -1;
+ else
+ compVal = compare((NodeCompareElem)b.elementAt(i),
(NodeCompareElem)b.elementAt(j), 0, support);
if(compVal < 0)
{
@@ -252,7 +330,7 @@
* @param lo0 left boundary of array partition
* @param hi0 right boundary of array partition
*/
- private void QuickSort2(Vector v, int lo0, int hi0, XPathSupport support)
+/* private void QuickSort2(Vector v, int lo0, int hi0, XPathSupport support)
throws org.xml.sax.SAXException,
java.net.MalformedURLException,
java.io.FileNotFoundException,
@@ -307,7 +385,7 @@
QuickSort2( v, lo, hi0, support );
}
}
- } // end QuickSort2
+ } // end QuickSort2 */
/**
* Simple function to swap two elements in
@@ -319,6 +397,55 @@
v.setElementAt(v.elementAt(j), i);
v.setElementAt(node, j);
}
+
+ class NodeCompareElem
+ {
+ Node m_node;
+ // This maxkey value was chosen arbitrarily. We are assuming that the
+ // maxkey + 1 keys will only hit fairly rarely and therefore, we
+ // will get the node values for those keys dynamically.
+ int maxkey = 2;
+ // Keep this in case we decide to use an array. Right now
+ // using two variables is cheaper.
+ //Object[] m_KeyValue = new Object[2];
+ Object m_key1Value;
+ Object m_key2Value;
+
+ NodeCompareElem(Node node) throws org.xml.sax.SAXException
+ {
+ m_node = node;
+ if (!m_keys.isEmpty())
+ {
+ NodeSortKey k1 = (NodeSortKey)m_keys.elementAt(0);
+ XObject r = k1.m_selectPat.execute(m_execContext, node,
k1.m_namespaceContext);
+ if(k1.m_treatAsNumbers)
+ m_key1Value = new Double(r.num());
+ else
+ m_key1Value = k1.m_col.getCollationKey(r.str());
+
+ if (m_keys.size()>1)
+ {
+ NodeSortKey k2 = (NodeSortKey)m_keys.elementAt(1);
+ XObject r2 = k2.m_selectPat.execute(m_execContext, node,
k2.m_namespaceContext);
+ if(k2.m_treatAsNumbers)
+ m_key2Value = new Double(r2.num());
+ else
+ m_key2Value = k2.m_col.getCollationKey(r2.str());
+ }
+ /* Leave this in case we decide to use an array later
+ while (kIndex <= m_keys.size() && kIndex < maxkey)
+ {
+ NodeSortKey k = (NodeSortKey)m_keys.elementAt(kIndex);
+ XObject r = k.m_selectPat.execute(m_execContext, node,
k.m_namespaceContext);
+ if(k.m_treatAsNumbers)
+ m_KeyValue[kIndex] = r.num();
+ else
+ m_KeyValue[kIndex] = r.str();
+ } */
+
+ } // end if not empty
+ }
+ } // end NodeCompareElem class
}