diff --git a/pom.xml b/pom.xml
index 74e7f0b7..08d381e6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -57,6 +57,18 @@ limitations under the License.
1.1
test
+
+ org.openjdk.jmh
+ jmh-core
+ 1.21
+ test
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ 1.21
+ test
+
diff --git a/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java b/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java
index e10498f1..49b25f89 100644
--- a/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java
+++ b/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java
@@ -23,9 +23,11 @@
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
/**
@@ -44,8 +46,6 @@ public class Xpp3Dom
protected final List childList;
- protected final Map childMap;
-
protected Xpp3Dom parent;
/**
@@ -88,7 +88,6 @@ public Xpp3Dom( String name )
{
this.name = name;
childList = new ArrayList();
- childMap = new HashMap();
}
/**
@@ -119,7 +118,6 @@ public Xpp3Dom( Xpp3Dom src, String name )
int childCount = src.getChildCount();
childList = new ArrayList( childCount );
- childMap = new HashMap( childCount << 1 );
setValue( src.getValue() );
@@ -170,13 +168,13 @@ public String[] getAttributeNames()
}
else
{
- return (String[]) attributes.keySet().toArray( new String[attributes.size()] );
+ return attributes.keySet().toArray( EMPTY_STRING_ARRAY );
}
}
public String getAttribute( String name )
{
- return ( null != attributes ) ? (String) attributes.get( name ) : null;
+ return ( null != attributes ) ? attributes.get( name ) : null;
}
/**
@@ -209,19 +207,30 @@ public void setAttribute( String name, String value )
public Xpp3Dom getChild( int i )
{
- return (Xpp3Dom) childList.get( i );
+ return childList.get( i );
}
public Xpp3Dom getChild( String name )
{
- return (Xpp3Dom) childMap.get( name );
+ if ( name != null )
+ {
+ ListIterator it = childList.listIterator( childList.size() );
+ while ( it.hasPrevious() )
+ {
+ Xpp3Dom child = it.previous();
+ if ( name.equals( child.getName() ) )
+ {
+ return child;
+ }
+ }
+ }
+ return null;
}
public void addChild( Xpp3Dom xpp3Dom )
{
xpp3Dom.setParent( this );
childList.add( xpp3Dom );
- childMap.put( xpp3Dom.getName(), xpp3Dom );
}
public Xpp3Dom[] getChildren()
@@ -232,31 +241,45 @@ public Xpp3Dom[] getChildren()
}
else
{
- return (Xpp3Dom[]) childList.toArray( new Xpp3Dom[childList.size()] );
+ return childList.toArray( EMPTY_DOM_ARRAY );
}
}
public Xpp3Dom[] getChildren( String name )
+ {
+ return getChildrenAsList( name ).toArray( EMPTY_DOM_ARRAY );
+ }
+
+ private List getChildrenAsList( String name )
{
if ( null == childList )
{
- return EMPTY_DOM_ARRAY;
+ return Collections.emptyList();
}
else
{
- ArrayList children = new ArrayList();
- int size = childList.size();
+ ArrayList children = null;
- for ( Xpp3Dom aChildList : childList )
+ for ( Xpp3Dom configuration : childList )
{
- Xpp3Dom configuration = (Xpp3Dom) aChildList;
if ( name.equals( configuration.getName() ) )
{
+ if ( children == null )
+ {
+ children = new ArrayList();
+ }
children.add( configuration );
}
}
- return (Xpp3Dom[]) children.toArray( new Xpp3Dom[children.size()] );
+ if ( children != null )
+ {
+ return children;
+ }
+ else
+ {
+ return Collections.emptyList();
+ }
}
}
@@ -273,7 +296,6 @@ public int getChildCount()
public void removeChild( int i )
{
Xpp3Dom child = getChild( i );
- childMap.values().remove( child );
childList.remove( i );
// In case of any dangling references
child.setParent( null );
@@ -392,12 +414,14 @@ private static void mergeIntoXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boole
dominant.setInputLocation( recessive.getInputLocation() );
}
- String[] recessiveAttrs = recessive.getAttributeNames();
- for ( String attr : recessiveAttrs )
+ if ( recessive.attributes != null )
{
- if ( isEmpty( dominant.getAttribute( attr ) ) )
+ for ( String attr : recessive.attributes.keySet() )
{
- dominant.setAttribute( attr, recessive.getAttribute( attr ) );
+ if ( isEmpty( dominant.getAttribute( attr ) ) )
+ {
+ dominant.setAttribute( attr, recessive.getAttribute( attr ) );
+ }
}
}
@@ -441,12 +465,16 @@ private static void mergeIntoXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boole
{
Map> commonChildren = new HashMap>();
- for ( String childName : recessive.childMap.keySet() )
+ for ( Xpp3Dom recChild : recessive.childList )
{
- Xpp3Dom[] dominantChildren = dominant.getChildren( childName );
- if ( dominantChildren.length > 0 )
+ if ( commonChildren.containsKey( recChild.name ) )
+ {
+ continue;
+ }
+ List dominantChildren = dominant.getChildrenAsList( recChild.name );
+ if ( dominantChildren.size() > 0 )
{
- commonChildren.put( childName, Arrays.asList( dominantChildren ).iterator() );
+ commonChildren.put( recChild.name, dominantChildren.iterator() );
}
}
diff --git a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomPerfTest.java b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomPerfTest.java
new file mode 100644
index 00000000..ee727595
--- /dev/null
+++ b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomPerfTest.java
@@ -0,0 +1,78 @@
+package org.codehaus.plexus.util.xml;
+
+/*
+ * Copyright The Codehaus Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.concurrent.TimeUnit;
+
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.TimeValue;
+
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS)
+public class Xpp3DomPerfTest
+{
+ @State(Scope.Benchmark)
+ static public class AdditionState {
+ Xpp3Dom dom1;
+ Xpp3Dom dom2;
+
+ @Setup(Level.Iteration)
+ public void setUp() throws IOException, XmlPullParserException {
+ String testDom = "- one
- two
";
+ dom1 = Xpp3DomBuilder.build( new StringReader( testDom ) );
+ dom2 = new Xpp3Dom( dom1 );
+ }
+ }
+
+
+ @Benchmark
+ public Xpp3Dom benchmarkClone(AdditionState state)
+ {
+ return new Xpp3Dom( state.dom1 );
+ }
+
+ @Benchmark
+ public void benchmarkMerge(AdditionState state)
+ {
+ Xpp3Dom.mergeXpp3Dom( state.dom1, state.dom2 );
+ }
+
+ public static void main(String... args) throws RunnerException {
+ Options opts = new OptionsBuilder()
+ .measurementIterations(3)
+ .measurementTime(TimeValue.milliseconds(3000))
+ .forks(1)
+ .build();
+ new Runner(opts).run();
+ }
+}