Minor refactoring in Emitter to improve performance: save calls to Constant.has()
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index ab5c80c..62a3575 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -7,6 +7,9 @@
</properties>
<body>
<release version="1.8-SNAPSHOT" date="in Mercurial" description="Performance improvement">
+ <action dev="py4fun" type="update">
+ Minor refactoring in Emitter to improve performance: save calls to Constant.has() (2010-09-13)
+ </action>
<action dev="maslovalex" type="update">
Minor refactorings in Emitter to improve performance: create less Strings [r9185e0b3] (2010-09-10)
</action>
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
index c263871..81b753d 100644
--- a/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
+++ b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
@@ -30,7 +30,6 @@
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
-import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.events.AliasEvent;
import org.yaml.snakeyaml.events.CollectionEndEvent;
import org.yaml.snakeyaml.events.CollectionStartEvent;
@@ -865,14 +864,6 @@
if ("!".equals(tag)) {
return tag;
}
- for (int i = 0; i < tag.length(); i++) {
- char ch = tag.charAt(i);
- if (Constant.URI_CHARS.hasNo(ch)) {
- // TODO Tag (URI) may not contain non-ASCII characters
- // (it seems that resources do not use proper encoding)
- throw new YAMLException("Tag (URI) may not contain non-ASCII characters.");
- }
- }
String handle = null;
String suffix = tag;
for (String prefix : tagPrefixes.keySet()) {
@@ -978,7 +969,8 @@
}
}
// Check for line breaks, special, and unicode characters.
- if (Constant.LINEBR.has(ch)) {
+ boolean isLineBreak = Constant.LINEBR.has(ch);
+ if (isLineBreak) {
lineBreaks = true;
}
if (!(ch == '\n' || ('\u0020' <= ch && ch <= '\u007E'))) {
@@ -1005,7 +997,7 @@
}
previousSpace = true;
previousBreak = false;
- } else if (Constant.LINEBR.has(ch)) {
+ } else if (isLineBreak) {
if (index == 0) {
leadingBreak = true;
}
@@ -1024,9 +1016,9 @@
// Prepare for the next character.
index++;
- preceededByWhitespace = Constant.NULL_BL_T_LINEBR.has(ch);
- followedByWhitespace = (index + 1 >= scalar.length() || Constant.NULL_BL_T_LINEBR
- .has(scalar.charAt(index + 1)));
+ preceededByWhitespace = Constant.NULL_BL_T.has(ch) || isLineBreak;
+ followedByWhitespace = (index + 1 >= scalar.length()
+ || (Constant.NULL_BL_T.has(scalar.charAt(index + 1))) || isLineBreak);
}
// Let's decide what styles are allowed.
boolean allowFlowPlain = true;
diff --git a/src/main/java/org/yaml/snakeyaml/scanner/Constant.java b/src/main/java/org/yaml/snakeyaml/scanner/Constant.java
index 346a32d..75b9b2d 100644
--- a/src/main/java/org/yaml/snakeyaml/scanner/Constant.java
+++ b/src/main/java/org/yaml/snakeyaml/scanner/Constant.java
@@ -26,6 +26,7 @@
private final static String NULL_OR_LINEBR_S = "\0" + FULL_LINEBR_S;
private final static String NULL_BL_LINEBR_S = " " + NULL_OR_LINEBR_S;
private final static String NULL_BL_T_LINEBR_S = "\t" + NULL_BL_LINEBR_S;
+ private final static String NULL_BL_T_S = "\0 \t";
private final static String URI_CHARS_S = ALPHA_S + "-;/?:@&=+$,_.!~*\'()[]%";
public final static Constant LINEBR = new Constant(LINEBR_S);
@@ -33,6 +34,7 @@
public final static Constant NULL_OR_LINEBR = new Constant(NULL_OR_LINEBR_S);
public final static Constant NULL_BL_LINEBR = new Constant(NULL_BL_LINEBR_S);
public final static Constant NULL_BL_T_LINEBR = new Constant(NULL_BL_T_LINEBR_S);
+ public final static Constant NULL_BL_T = new Constant(NULL_BL_T_S);
public final static Constant URI_CHARS = new Constant(URI_CHARS_S);
public final static Constant ALPHA = new Constant(ALPHA_S);
diff --git a/src/test/java/org/yaml/snakeyaml/StressEmitterTest.java b/src/test/java/org/yaml/snakeyaml/StressEmitterTest.java
new file mode 100644
index 0000000..f9da446
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/StressEmitterTest.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2008-2010, http://code.google.com/p/snakeyaml/
+ *
+ * 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.
+ */
+
+package org.yaml.snakeyaml;
+
+import java.io.IOException;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class StressEmitterTest extends TestCase {
+
+ public static void main(String args[]) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite() {
+ return new TestSuite(StressEmitterTest.class);
+ }
+
+ public void testPerformance() throws IOException {
+ JavaBeanLoader<Invoice> loader = new JavaBeanLoader<Invoice>(Invoice.class);
+ Invoice invoice = loader.load(Util.getLocalResource("specification/example2_27.yaml"));
+ JavaBeanDumper dumper = new JavaBeanDumper();
+ long time1 = System.nanoTime();
+ dumper.dump(invoice);
+ long time2 = System.nanoTime();
+ float duration = (time2 - time1) / 1000000;
+ System.out.println("\nSingle dump was " + duration + " ms.");
+
+ int[] range = new int[] { 1000, 2000 /* , 8000 */};
+ System.out.println("\nOne instance.");
+ for (int number : range) {
+ time1 = System.nanoTime();
+ for (int i = 0; i < number; i++) {
+ dumper.dump(invoice);
+ }
+ time2 = System.nanoTime();
+ duration = ((time2 - time1) / 1000000) / (float) number;
+ System.out.println("Duration for r=" + number + " was " + duration + " ms/dump.");
+ // cobertura may make it very slow
+ if (duration > 3) {
+ System.err.println("!!!!!! Too long. Expected <1 but was " + duration);
+ }
+ }
+
+ System.out.println("\nMany instances.");
+ for (int number : range) {
+ time1 = System.nanoTime();
+ for (int i = 0; i < number; i++) {
+ dumper = new JavaBeanDumper();
+ dumper.dump(invoice);
+ }
+ time2 = System.nanoTime();
+ duration = ((time2 - time1) / 1000000) / (float) number;
+ System.out.println("Duration for r=" + number + " was " + duration + " ms/dump.");
+ // cobertura may make it very slow
+ if (duration > 3) {
+ System.err.println("!!!!!! Too long. Expected <1 but was " + duration);
+ }
+ // assertTrue("duration=" + duration, duration < 3);
+ }
+ }
+}
\ No newline at end of file