Hi,

I have prepared patch for NSStack, moving from growing number of Vectors to
3 arrays per stack.
I also used intern() String comparison, but this only do benefits for large
number of comparisons, and it may happen that having just String.equals()
could be better. Can anybody say how many namespaces goes into array
typically?

Pavel

Index: NSStack.java
===================================================================
RCS file: /home/cvspublic/xml-soap/java/src/org/apache/soap/util/xml/NSStack.java,v
retrieving revision 1.4
diff -u -r1.4 NSStack.java
--- NSStack.java        10 Nov 2000 15:20:58 -0000      1.4
+++ NSStack.java        14 Nov 2002 14:00:16 -0000
@@ -2,7 +2,7 @@
  * The Apache Software License, Version 1.1
  *
  *
- * Copyright (c) 2000 The Apache Software Foundation.  All rights 
+ * Copyright (c) 2000 The Apache Software Foundation.  All rights
  * reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -10,7 +10,7 @@
  * are met:
  *
  * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer. 
+ *    notice, this list of conditions and the following disclaimer.
  *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
@@ -18,7 +18,7 @@
  *    distribution.
  *
  * 3. The end-user documentation included with the redistribution,
- *    if any, must include the following acknowledgment:  
+ *    if any, must include the following acknowledgment:
  *       "This product includes software developed by the
  *        Apache Software Foundation (http://www.apache.org/)."
  *    Alternately, this acknowledgment may appear in the software itself,
@@ -26,7 +26,7 @@
  *
  * 4. The names "SOAP" and "Apache Software Foundation" must
  *    not be used to endorse or promote products derived from this
- *    software without prior written permission. For written 
+ *    software without prior written permission. For written
  *    permission, please contact [EMAIL PROTECTED]
  *
  * 5. Products derived from this software may not be called "Apache",
@@ -59,7 +59,8 @@
 
 import java.io.*;
 import java.util.*;
-import org.apache.soap.util.xml.* ;
+
+import org.apache.soap.util.xml.*;
 
 /**
  * This class implements a namespace stack for XML apps to use. If
@@ -79,134 +80,198 @@
  * declaration.
  *
  * @author Sanjiva Weerawarana ([EMAIL PROTECTED])
+ * @author Pavel Ausianik <[EMAIL PROTECTED]>
  */
-public class NSStack {
-  Vector nss = new Vector (); // vector holding vectors of ns decls (stack)
-  int nssCount = 0;           // number of items on the stack
-  Vector tos;                 // the vector @ the top of the stack
-  private final static String nsPrefixPrefix = "ns";
-  private int nsPrefixCount = 1;
-
-  /**
-   * Enter a new scope: after calling this I'm ready to accept new
-   * declarations into that scope.
-   */
-  public void pushScope () {
-    nss.addElement (tos = new Vector ());
-    nssCount++;
-  }
-
-  /**
-   * Leave a scope: this removes any NS declarations that were added
-   * in the last scope. Note that I don't bother to validate that you
-   * don't call popScope too many times; that's your problem.
-   */
-  public void popScope () {
-    nss.removeElementAt (--nssCount);
-    tos = (nssCount != 0) ? (Vector) nss.elementAt (nssCount-1) : null;
-  }
-
-  /**
-   * Add a new declaration to the current scope. This is visible within
-   * the current scope as well as from any nested scopes. 
-   *
-   * @param prefix the prefix to be used for this namespace
-   * @param URI the namespace name of this namespace.
-   */
-  synchronized public void addNSDeclaration (String prefix, String URI) {
-    tos.addElement (new NSDecl (prefix, URI));
-  }
-
-  /**
-   * Add a new declaration to the current scope using a unique prefix
-   * and return the prefix. This is useful when one just wants to add a
-   * decl and doesn't want to have to deal with creating unique prefixes.
-   * If the namespace name is already declared and in scope, then the 
-   * previously declared prefix is returned.
-   *
-   * @param URI the namespace name of this namespace
-   * @return the unique prefix created or previously declared
-   *         for this namespace
-   */
-  synchronized public String addNSDeclaration (String URI) {
-    String uniquePrefix = getPrefixFromURI (URI);
-    if (uniquePrefix == null) {
-      do {
-              uniquePrefix = nsPrefixPrefix + nsPrefixCount++;
-      } while (getURIFromPrefix (uniquePrefix) != null);
-      addNSDeclaration (uniquePrefix, URI);
-    }
-    return uniquePrefix;
-  }
-
-  /**
-   * Return the prefix associated with the given namespace name by
-   * looking thru all the namespace declarations that are in scope.
-   *
-   * @param URI the namespace name for whom a declared prefix is desired
-   * @return the prefix or null if namespace name not found
-   */
-  public String getPrefixFromURI (String URI) {
-    for (int i = nssCount-1; i >= 0; i--) {
-      Vector scope = (Vector) nss.elementAt (i);
-      for (Enumeration e = scope.elements (); e.hasMoreElements (); ) {
-        NSDecl nsd = (NSDecl) e.nextElement ();
-        if (nsd.URI.equals (URI)) {
-          return nsd.prefix;
-        }
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Return the prefix associated with the given namespace name by
-   * looking thru all the namespace declarations that are in scope.
-   * If the namespace declaration is not found, create one and
-   * return the generated prefix.
-   *
-   * @param URI the namespace name for whom a declared prefix is desired
-   * @return the prefix (will never return null)
-   */
-  synchronized public String getPrefixFromURI (String namespaceURI,
-                                               Writer sink)
-    throws IOException {
-    String prefix = getPrefixFromURI (namespaceURI);
-
-    if (prefix == null) {
-      prefix = addNSDeclaration (namespaceURI);
-
-      sink.write (" xmlns:" + prefix + "=\"" + namespaceURI + '\"');
-    }
-
-    return prefix;
-  }
-
-  /**
-   * Return the namespace name associated with the given prefix by
-   * looking thru all the namespace declarations that are in scope.
-   *
-   * @param prefix the prefix for whom a declared namespace name is desired
-   * @return the namespace name or null if prefix not found
-   */
-  public String getURIFromPrefix (String prefix) {
-    for (int i = nssCount-1; i >= 0; i--) {
-      Vector scope = (Vector) nss.elementAt (i);
-      for (Enumeration e = scope.elements (); e.hasMoreElements (); ) {
-        NSDecl nsd = (NSDecl) e.nextElement ();
-        if (nsd.prefix.equals (prefix)) {
-          return nsd.URI;
-        }
-      }
-    }
-    return null;
-  }
-
-  // MJD - debug
-  public String toString()
-  {
-    return nss.toString();
-  }
-  // MJD - debug
+public final class NSStack {
+    private String[] URIStack;
+    private String[] prefixStack;
+
+    private int[] scope;
+    private int top = 0;
+    private int iterator = -1;
+    private final static String NSPREFIX = "ns";
+    private int nsPrefixCount = 0;
+
+    private static String[] predefinedNamespaces;
+
+    private static final int START_ARRAY_SIZE = 32;
+
+    public NSStack() {
+        URIStack = new String[START_ARRAY_SIZE];
+        prefixStack = new String[START_ARRAY_SIZE];
+        scope = new int[START_ARRAY_SIZE];
+        scope[0] = -1;
+    }
+
+    /**
+     * Creates a predefined Namespace string
+     * Assuming that in the single application , the number of names is the same
+     * between calls. We'll benefit from caching on continuous operations
+     */
+    synchronized private static String getPredefinedNamespace(int nsCount) {
+        if (predefinedNamespaces == null)
+        {
+            predefinedNamespaces =  new String[START_ARRAY_SIZE];
+            for (int i=0; i<START_ARRAY_SIZE; i++)
+                predefinedNamespaces[i] = NSPREFIX + (i+1);
+        } else if (nsCount >= predefinedNamespaces.length) {
+            int length  = predefinedNamespaces.length;
+            String[] newnamespace = new String[length * 2];
+            System.arraycopy(predefinedNamespaces, 0, newnamespace, 0, length);
+            for (int i=0; i<length; i++)
+                predefinedNamespaces[i+length] = NSPREFIX + (i+length+1);
+        }
+        return predefinedNamespaces[nsCount];
+    }
+
+    /**
+     * Enter a new scope: after calling this I'm ready to accept new
+     * declarations into that scope.
+     */
+    public void pushScope() {
+
+        top++;
+        int length = scope.length;
+
+        if (top >= length) {
+            int newscope[] = new int[length * 2];
+            System.arraycopy(scope, 0, newscope, 0, length);
+            scope = newscope;
+        }
+
+        scope[top] = iterator;
+
+    }
+
+    /**
+     * Leave a scope: this removes any NS declarations that were added
+     * in the last scope. Note that I don't bother to validate that you
+     * don't call popScope too many times; that's your problem.
+     */
+    public void popScope() {
+        scope[top] = 0;
+        top--;
+        iterator = top >= 0 ? scope[top] : 0;
+    }
+
+    /**
+     * Add a new declaration to the current scope. This is visible within
+     * the current scope as well as from any nested scopes.
+     *
+     * @param prefix the prefix to be used for this namespace
+     * @param URI the namespace name of this namespace.
+     */
+    public void addNSDeclaration(String prefix, String namespaceURI) {
+        int length = URIStack.length;
+        iterator++;
+
+        if (iterator >= length) {
+            String newstack[] = new String[length * 2];
+            System.arraycopy(URIStack, 0, newstack, 0, length);
+            URIStack = newstack;
+            newstack = new String[length * 2];
+            System.arraycopy(prefixStack, 0, newstack, 0, length);
+            prefixStack = newstack;
+        }
+        // scope too small - expand - very unlikely
+        URIStack[iterator] = namespaceURI.intern();
+        prefixStack[iterator] = prefix.intern();
+    }
+
+    /**
+     * Add a new declaration to the current scope using a unique prefix
+     * and return the prefix. This is useful when one just wants to add a
+     * decl and doesn't want to have to deal with creating unique prefixes.
+     * If the namespace name is already declared and in scope, then the
+     * previously declared prefix is returned.
+     *
+     * @param URI the namespace name of this namespace
+     * @return the unique prefix created or previously declared
+     *         for this namespace
+     */
+    public String addNSDeclaration(String URI) {
+        String uniquePrefix = getPrefixFromURI(URI);
+        if (uniquePrefix == null) {
+            do {
+                uniquePrefix = getPredefinedNamespace(nsPrefixCount++);
+            } while (getURIFromPrefix(uniquePrefix) != null);
+            addNSDeclaration(uniquePrefix, URI);
+        }
+        return uniquePrefix;
+    }
+
+    /**
+     * Return the prefix associated with the given namespace name by
+     * looking thru all the namespace declarations that are in scope.
+     *
+     * @param URI the namespace name for whom a declared prefix is desired
+     * @return the prefix or null if namespace name not found
+     */
+    public String getPrefixFromURI(String namespaceURI) {
+        if ((namespaceURI == null) || (namespaceURI.equals("")))
+            return null;
+
+        namespaceURI = namespaceURI.intern();
+        for (int cursor = iterator; cursor >= 0; cursor--) {
+            if (URIStack[cursor] == namespaceURI)
+                return prefixStack[cursor];
+        }
+        return null;
+    }
+
+    /**
+     * Return the prefix associated with the given namespace name by
+     * looking thru all the namespace declarations that are in scope.
+     * If the namespace declaration is not found, create one and
+     * return the generated prefix.
+     *
+     * @param URI the namespace name for whom a declared prefix is desired
+     * @return the prefix (will never return null)
+     */
+    public String getPrefixFromURI(String namespaceURI, Writer sink)
+            throws IOException {
+        String prefix = getPrefixFromURI(namespaceURI);
+
+        if (prefix == null) {
+            prefix = addNSDeclaration(namespaceURI);
+
+            sink.write(" xmlns:");
+            sink.write(prefix);
+            sink.write("=\"");
+            sink.write(namespaceURI);
+            sink.write('\"');
+        }
+
+        return prefix;
+    }
+
+    /**
+     * Given a prefix, return the associated namespace (if any).
+     */
+    public String getURIFromPrefix(String prefix) {
+        if (prefix == null)
+            prefix = "";
+        prefix = prefix.intern();
+        for (int cursor = iterator; cursor >= 0; cursor--) {
+                if (prefixStack[cursor] ==  prefix)
+                    return URIStack[cursor];
+        }
+
+        return null;
+    }
+
+    public void dump() {
+        int end = iterator;
+        int start = 0;
+        for (int cursor = top; cursor >= 0; cursor--, end = start - 1) {
+            start = scope[cursor] + 1;
+
+            System.out.println("Level: " + cursor);
+
+            for (int j = start; j <= end; j++) {
+                System.out.println("    Map:" + URIStack[cursor] + " -> " 
++prefixStack[cursor]);
+            }
+        }
+    }
 }
 

--
To unsubscribe, e-mail:   <mailto:soap-dev-unsubscribe@;xml.apache.org>
For additional commands, e-mail: <mailto:soap-dev-help@;xml.apache.org>

Reply via email to