You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2016/05/31 02:01:02 UTC
[2/3] groovy git commit: GROOVY-6950: StringGroovyMethods minor
performance improvements (make use of line based iterator)
GROOVY-6950: StringGroovyMethods minor performance improvements (make use of line based iterator)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/35b5f345
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/35b5f345
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/35b5f345
Branch: refs/heads/master
Commit: 35b5f3450788601e5bad8a18b5a4758663fedebb
Parents: 24043a5
Author: paulk <pa...@asert.com.au>
Authored: Mon May 30 21:11:46 2016 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Mon May 30 21:11:46 2016 +1000
----------------------------------------------------------------------
.../groovy/runtime/StringGroovyMethods.java | 146 ++++++----------
.../groovy/util/CharSequenceReader.java | 170 +++++++++++++++++++
2 files changed, 226 insertions(+), 90 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/35b5f345/src/main/org/codehaus/groovy/runtime/StringGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/runtime/StringGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/StringGroovyMethods.java
index 058b270..665f606 100644
--- a/src/main/org/codehaus/groovy/runtime/StringGroovyMethods.java
+++ b/src/main/org/codehaus/groovy/runtime/StringGroovyMethods.java
@@ -29,6 +29,7 @@ import groovy.transform.stc.FromString;
import groovy.transform.stc.PickFirstResolver;
import groovy.transform.stc.SimpleType;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.util.CharSequenceReader;
import java.io.BufferedWriter;
import java.io.File;
@@ -40,6 +41,7 @@ import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -47,6 +49,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.StringTokenizer;
+import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -69,36 +72,6 @@ import static org.codehaus.groovy.runtime.DefaultGroovyMethods.join;
* at the Java method call level. I.e. future versions of Groovy may
* remove or move a method call in this file but would normally
* aim to keep the method available from within Groovy.
- *
- * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
- * @author Jeremy Rayner
- * @author Sam Pullara
- * @author Rod Cope
- * @author Guillaume Laforge
- * @author John Wilson
- * @author Hein Meling
- * @author Dierk Koenig
- * @author Pilho Kim
- * @author Marc Guillemot
- * @author Russel Winder
- * @author bing ran
- * @author Jochen Theodorou
- * @author Paul King
- * @author Michael Baehr
- * @author Joachim Baumann
- * @author Alex Tkachman
- * @author Ted Naleid
- * @author Brad Long
- * @author Jim Jagielski
- * @author Rodolfo Velasco
- * @author jeremi Joslin
- * @author Hamlet D'Arcy
- * @author Cedric Champeau
- * @author Tim Yates
- * @author Dinko Srkoc
- * @author Pascal Lombard
- * @author Christophe Charles
- * @author Andres Almiray
*/
public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
@@ -339,15 +312,14 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
* @since 1.8.2
*/
public static String center(CharSequence self, Number numberOfChars, CharSequence padding) {
- String padding1 = padding.toString();
int numChars = numberOfChars.intValue();
if (numChars <= self.length()) {
return self.toString();
} else {
int charsToAdd = numChars - self.length();
String semiPad = charsToAdd % 2 == 1 ?
- getPadding(padding1, charsToAdd / 2 + 1) :
- getPadding(padding1, charsToAdd / 2);
+ getPadding(padding, charsToAdd / 2 + 1) :
+ getPadding(padding, charsToAdd / 2);
if (charsToAdd % 2 == 0)
return semiPad + self + semiPad;
else
@@ -628,6 +600,19 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
}
}
+ private static final class LineIterable implements Iterable<String> {
+ private final CharSequence delegate;
+
+ public LineIterable(CharSequence cs) {
+ this.delegate = cs;
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ return IOGroovyMethods.iterator(new CharSequenceReader(delegate));
+ }
+ }
+
/**
* Iterates through this CharSequence line by line. Each line is passed
* to the given 1 or 2 arg closure. If a 2 arg closure is found
@@ -660,7 +645,7 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
public static <T> T eachLine(CharSequence self, int firstLine, @ClosureParams(value=FromString.class, options={"String","String,Integer"}) Closure<T> closure) throws IOException {
int count = firstLine;
T result = null;
- for (String line : readLines((CharSequence)self.toString())) {
+ for (String line : new LineIterable(self)) {
result = callClosureForLine(closure, line, count);
count++;
}
@@ -822,22 +807,17 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
* @since 1.8.2
*/
public static String expand(CharSequence self, int tabStop) {
- if (self.length() == 0) return self.toString();
- try {
- StringBuilder builder = new StringBuilder();
- for (String line : readLines(self)) {
- builder.append(expandLine((CharSequence)line, tabStop));
- builder.append("\n");
- }
- // remove the normalized ending line ending if it was not present
- if (self.charAt(self.length() - 1) != '\n') {
- builder.deleteCharAt(builder.length() - 1);
- }
- return builder.toString();
- } catch (IOException e) {
- /* ignore */
+ if (self.length() == 0) return "";
+ StringBuilder builder = new StringBuilder();
+ for (String line : new LineIterable(self)) {
+ builder.append(expandLine((CharSequence)line, tabStop));
+ builder.append("\n");
}
- return self.toString();
+ // remove the normalized ending line ending if it was not present
+ if (self.charAt(self.length() - 1) != '\n') {
+ builder.deleteCharAt(builder.length() - 1);
+ }
+ return builder.toString();
}
/**
@@ -3126,16 +3106,12 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
public static String stripIndent(CharSequence self) {
if (self.length() == 0) return self.toString();
int runningCount = -1;
- try {
- for (String line : readLines(self)) {
- // don't take blank lines into account for calculating the indent
- if (isAllWhitespace((CharSequence) line)) continue;
- if (runningCount == -1) runningCount = line.length();
- runningCount = findMinimumLeadingSpaces(line, runningCount);
- if (runningCount == 0) break;
- }
- } catch (IOException e) {
- /* ignore */
+ for (String line : new LineIterable(self)) {
+ // don't take blank lines into account for calculating the indent
+ if (isAllWhitespace((CharSequence) line)) continue;
+ if (runningCount == -1) runningCount = line.length();
+ runningCount = findMinimumLeadingSpaces(line, runningCount);
+ if (runningCount == 0) break;
}
return stripIndent(self, runningCount == -1 ? 0 : runningCount);
}
@@ -3154,25 +3130,20 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
*/
public static String stripIndent(CharSequence self, int numChars) {
if (self.length() == 0 || numChars <= 0) return self.toString();
- try {
- StringBuilder builder = new StringBuilder();
- for (String line : readLines(self)) {
- // normalize an empty or whitespace line to \n
- // or strip the indent for lines containing non-space characters
- if (!isAllWhitespace((CharSequence) line)) {
- builder.append(stripIndentFromLine(line, numChars));
- }
- builder.append("\n");
+ StringBuilder builder = new StringBuilder();
+ for (String line : new LineIterable(self)) {
+ // normalize an empty or whitespace line to \n
+ // or strip the indent for lines containing non-space characters
+ if (!isAllWhitespace((CharSequence) line)) {
+ builder.append(stripIndentFromLine(line, numChars));
}
- // remove the normalized ending line ending if it was not present
- if (self.charAt(self.length() - 1) != '\n') {
- builder.deleteCharAt(builder.length() - 1);
- }
- return builder.toString();
- } catch (IOException e) {
- /* ignore */
+ builder.append("\n");
}
- return self.toString();
+ // remove the normalized ending line ending if it was not present
+ if (self.charAt(self.length() - 1) != '\n') {
+ builder.deleteCharAt(builder.length() - 1);
+ }
+ return builder.toString();
}
/**
@@ -3234,21 +3205,16 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
*/
public static String stripMargin(CharSequence self, char marginChar) {
if (self.length() == 0) return self.toString();
- try {
- StringBuilder builder = new StringBuilder();
- for (String line : readLines(self)) {
- builder.append(stripMarginFromLine(line, marginChar));
- builder.append("\n");
- }
- // remove the normalized ending line ending if it was not present
- if (self.charAt(self.length() - 1) != '\n') {
- builder.deleteCharAt(builder.length() - 1);
- }
- return builder.toString();
- } catch (IOException e) {
- /* ignore */
+ StringBuilder builder = new StringBuilder();
+ for (String line : new LineIterable(self)) {
+ builder.append(stripMarginFromLine(line, marginChar));
+ builder.append("\n");
}
- return self.toString();
+ // remove the normalized ending line ending if it was not present
+ if (self.charAt(self.length() - 1) != '\n') {
+ builder.deleteCharAt(builder.length() - 1);
+ }
+ return builder.toString();
}
/**
http://git-wip-us.apache.org/repos/asf/groovy/blob/35b5f345/src/main/org/codehaus/groovy/util/CharSequenceReader.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/util/CharSequenceReader.java b/src/main/org/codehaus/groovy/util/CharSequenceReader.java
new file mode 100644
index 0000000..2154002
--- /dev/null
+++ b/src/main/org/codehaus/groovy/util/CharSequenceReader.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.codehaus.groovy.util;
+
+import java.io.Reader;
+import java.io.Serializable;
+
+/**
+ * {@link Reader} implementation that can read from String, StringBuffer,
+ * StringBuilder, CharBuffer or GString.
+ * <p>
+ * <strong>Note:</strong> Supports {@link #mark(int)} and {@link #reset()}.
+ */
+public class CharSequenceReader extends Reader implements Serializable {
+ /*
+ NOTE: nearly 100% borrowed from Commons-IO but we don't want to bring
+ in that whole package just yet. We need to consider reworking all of our
+ IO in light of Java 8 streams and decide whether it makes sense to bring
+ in an external package.
+ */
+ private static final long serialVersionUID = -6661279371843310693L;
+ private final CharSequence charSequence;
+ private int idx;
+ private int mark;
+ private static final int EOF = -1;
+
+ /**
+ * Construct a new instance with the specified character sequence.
+ *
+ * @param charSequence The character sequence, may be {@code null}
+ */
+ public CharSequenceReader(final CharSequence charSequence) {
+ this.charSequence = charSequence != null ? charSequence : "";
+ }
+
+ /**
+ * Close resets the reader back to the start and removes any marked position.
+ */
+ @Override
+ public void close() {
+ idx = 0;
+ mark = 0;
+ }
+
+ /**
+ * Mark the current position.
+ *
+ * @param readAheadLimit ignored
+ */
+ @Override
+ public void mark(final int readAheadLimit) {
+ mark = idx;
+ }
+
+ /**
+ * Mark is supported (returns true).
+ *
+ * @return {@code true}
+ */
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ /**
+ * Read a single character.
+ *
+ * @return the next character from the character sequence
+ * or -1 if the end has been reached.
+ */
+ @Override
+ public int read() {
+ if (idx >= charSequence.length()) {
+ return EOF;
+ } else {
+ return charSequence.charAt(idx++);
+ }
+ }
+
+ /**
+ * Read the sepcified number of characters into the array.
+ *
+ * @param array The array to store the characters in
+ * @param offset The starting position in the array to store
+ * @param length The maximum number of characters to read
+ * @return The number of characters read or -1 if there are
+ * no more
+ */
+ @Override
+ public int read(final char[] array, final int offset, final int length) {
+ if (idx >= charSequence.length()) {
+ return EOF;
+ }
+ if (array == null) {
+ throw new NullPointerException("Character array is missing");
+ }
+ if (length < 0 || offset < 0 || offset + length > array.length) {
+ throw new IndexOutOfBoundsException("Array Size=" + array.length +
+ ", offset=" + offset + ", length=" + length);
+ }
+ int count = 0;
+ for (int i = 0; i < length; i++) {
+ final int c = read();
+ if (c == EOF) {
+ return count;
+ }
+ array[offset + i] = (char)c;
+ count++;
+ }
+ return count;
+ }
+
+ /**
+ * Reset the reader to the last marked position (or the beginning if
+ * mark has not been called).
+ */
+ @Override
+ public void reset() {
+ idx = mark;
+ }
+
+ /**
+ * Skip the specified number of characters.
+ *
+ * @param n The number of characters to skip
+ * @return The actual number of characters skipped
+ */
+ @Override
+ public long skip(final long n) {
+ if (n < 0) {
+ throw new IllegalArgumentException(
+ "Number of characters to skip is less than zero: " + n);
+ }
+ if (idx >= charSequence.length()) {
+ return EOF;
+ }
+ final int dest = (int)Math.min(charSequence.length(), idx + n);
+ final int count = dest - idx;
+ idx = dest;
+ return count;
+ }
+
+ /**
+ * Return a String representation of the underlying
+ * character sequence.
+ *
+ * @return The contents of the character sequence
+ */
+ @Override
+ public String toString() {
+ return charSequence.toString();
+ }
+}
\ No newline at end of file