[Jython-checkins] jython: Remove redundant copies of code, related to formatting, now moved to stringlib.
jeff.allen
jython-checkins at python.org
Sun Jun 8 14:13:09 CEST 2014
http://hg.python.org/jython/rev/234d1492dde4
changeset: 7286:234d1492dde4
user: Jeff Allen <ja.py at farowl.co.uk>
date: Sun Jun 08 07:44:48 2014 +0100
summary:
Remove redundant copies of code, related to formatting, now moved to stringlib.
files:
src/org/python/core/PyInteger.java | 107 ---------
src/org/python/core/stringlib/InternalFormatSpec.java | 88 -------
src/org/python/core/stringlib/InternalFormatSpecParser.java | 118 ----------
tests/java/org/python/core/StringFormatTest.java | 39 +-
4 files changed, 22 insertions(+), 330 deletions(-)
diff --git a/src/org/python/core/PyInteger.java b/src/org/python/core/PyInteger.java
--- a/src/org/python/core/PyInteger.java
+++ b/src/org/python/core/PyInteger.java
@@ -1106,113 +1106,6 @@
}
}
- /**
- * A more efficient algorithm for generating a hexadecimal representation of a byte array.
- * {@link BigInteger#toString(int)} is too slow because it generalizes to any radix and,
- * consequently, is implemented using expensive mathematical operations.
- *
- * @param value the value to generate a hexadecimal string from
- * @return the hexadecimal representation of value, with "-" sign prepended if necessary
- */
- static final String toHexString(BigInteger value) {
- int signum = value.signum();
-
- // obvious shortcut
- if (signum == 0) {
- return "0";
- }
-
- // we want to work in absolute numeric value (negative sign is added afterward)
- byte[] input = value.abs().toByteArray();
- StringBuilder sb = new StringBuilder(input.length * 2);
-
- int b;
- for (int i = 0; i < input.length; i++) {
- b = input[i] & 0xFF;
- sb.append(LOOKUP.charAt(b >> 4));
- sb.append(LOOKUP.charAt(b & 0x0F));
- }
-
- // before returning the char array as string, remove leading zeroes, but not the last one
- String result = sb.toString().replaceFirst("^0+(?!$)", "");
- return signum < 0 ? "-" + result : result;
- }
-
- /**
- * A more efficient algorithm for generating an octal representation of a byte array.
- * {@link BigInteger#toString(int)} is too slow because it generalizes to any radix and,
- * consequently, is implemented using expensive mathematical operations.
- *
- * @param value the value to generate an octal string from
- * @return the octal representation of value, with "-" sign prepended if necessary
- */
- static final String toOctString(BigInteger value) {
- int signum = value.signum();
-
- // obvious shortcut
- if (signum == 0) {
- return "0";
- }
-
- byte[] input = value.abs().toByteArray();
- if (input.length < 3) {
- return value.toString(8);
- }
-
- StringBuilder sb = new StringBuilder(input.length * 3);
-
- // working backwards, three bytes at a time
- int threebytes;
- int trip1, trip2, trip3; // most, middle, and least significant bytes in the triplet
- for (int i = input.length - 1; i >= 0; i -= 3) {
- trip3 = input[i] & 0xFF;
- trip2 = ((i - 1) >= 0) ? (input[i - 1] & 0xFF) : 0x00;
- trip1 = ((i - 2) >= 0) ? (input[i - 2] & 0xFF) : 0x00;
- threebytes = trip3 | (trip2 << 8) | (trip1 << 16);
-
- // convert the three-byte value into an eight-character octal string
- for (int j = 0; j < 8; j++) {
- sb.append(LOOKUP.charAt((threebytes >> (j * 3)) & 0x000007));
- }
- }
-
- String result = sb.reverse().toString().replaceFirst("^0+(?!%)", "");
- return signum < 0 ? "-" + result : result;
- }
-
- /**
- * A more efficient algorithm for generating a binary representation of a byte array.
- * {@link BigInteger#toString(int)} is too slow because it generalizes to any radix and,
- * consequently, is implemented using expensive mathematical operations.
- *
- * @param value the value to generate a binary string from
- * @return the binary representation of value, with "-" sign prepended if necessary
- */
- static final String toBinString(BigInteger value) {
- int signum = value.signum();
-
- // obvious shortcut
- if (signum == 0) {
- return "0";
- }
-
- // we want to work in absolute numeric value (negative sign is added afterward)
- byte[] input = value.abs().toByteArray();
- StringBuilder sb = new StringBuilder(value.bitCount());
-
- int b;
- for (int i = 0; i < input.length; i++) {
- b = input[i] & 0xFF;
- for (int bit = 7; bit >= 0; bit--) {
- sb.append(((b >> bit) & 0x1) > 0 ? "1" : "0");
- }
- }
-
- // before returning the char array as string, remove leading zeroes, but not the last one
- String result = sb.toString().replaceFirst("^0+(?!$)", "");
- return signum < 0 ? "-" + result : result;
- }
-
@Override
public boolean isIndex() {
return true;
diff --git a/src/org/python/core/stringlib/InternalFormatSpec.java b/src/org/python/core/stringlib/InternalFormatSpec.java
deleted file mode 100644
--- a/src/org/python/core/stringlib/InternalFormatSpec.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.python.core.stringlib;
-
-/**
- * Parsed PEP-3101 format specification of a single field. This class holds the several attributes
- * that might be decoded from a format specifier. It provides a method
- * {@link #pad(String, char, int)} for adjusting a string using those attributes related to padding
- * to a string assumed to be the result of formatting to the given precision.
- * <p>
- * This structure is returned by {@link InternalFormatSpecParser#parse()} and having public members
- * is freely used by {@link InternalFormatSpecParser}, and the __format__ methods of client object
- * types.
- * <p>
- * The fields correspond to the elements of a format specification. The grammar of a format
- * specification is:
- *
- * <pre>
- * [[fill]align][sign][#][0][width][,][.precision][type]
- * </pre>
- */
-public final class InternalFormatSpec {
-
- /** The fill specified in the grammar. */
- public char fill_char;
- /** Alignment indicator is 0, or one of {<code>'<', '^', '>', '='</code> . */
- public char align;
- /** The alternative format flag '#' was given. */
- public boolean alternate;
- /** Sign-handling flag, one of <code>'+'</code>, <code>'-'</code>, or <code>' '</code>. */
- public char sign;
- /** Width to which to pad the resault in {@link #pad(String, char, int)}. */
- public int width = -1;
- /** Insert the grouping separator (which in Python always indicates a group-size of 3). */
- public boolean thousands_separators;
- /** Precision decoded from the format. */
- public int precision = -1;
- /** Type key from the format. */
- public char type;
-
- /**
- * Pad value, using {@link #fill_char} (or <code>' '</code>) before and after, to {@link #width}
- * <code>-leaveWidth</code>, aligned according to {@link #align} (or according to
- * <code>defaultAlign</code>).
- *
- * @param value to pad
- * @param defaultAlign to use if <code>this.align</code>=0 (one of <code>'<'</code>,
- * <code>'^'</code>, <code>'>'</code>, or <code>'='</code>).
- * @param leaveWidth to reduce effective <code>this.width</code> by
- * @return padded value
- */
- public String pad(String value, char defaultAlign, int leaveWidth) {
-
- // We'll need this many pad characters (if>0)
- int remaining = width - value.length() - leaveWidth;
- if (remaining <= 0) {
- return value;
- }
-
- // Use this.align or defaultAlign
- int useAlign = align;
- if (useAlign == 0) {
- useAlign = defaultAlign;
- }
-
- // By default all padding is leading padding ('<' case or '=')
- int leading = remaining;
- if (useAlign == '^') {
- // Half the padding before
- leading = remaining / 2;
- } else if (useAlign == '<') {
- // All the padding after
- leading = 0;
- }
-
- // Now build the result
- StringBuilder result = new StringBuilder();
- char fill = fill_char != 0 ? fill_char : ' ';
-
- for (int i = 0; i < leading; i++) { // before
- result.append(fill);
- }
- result.append(value);
- for (int i = 0; i < remaining - leading; i++) { // after
- result.append(fill);
- }
-
- return result.toString();
- }
-}
diff --git a/src/org/python/core/stringlib/InternalFormatSpecParser.java b/src/org/python/core/stringlib/InternalFormatSpecParser.java
deleted file mode 100644
--- a/src/org/python/core/stringlib/InternalFormatSpecParser.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.python.core.stringlib;
-
-/**
- * Parser for PEP-3101 field format specifications. This class provides a {@link #parse()} method
- * that translates the format specification into an <code>InternalFormatSpec</code> object.
- */
-public class InternalFormatSpecParser {
-
- private String spec;
- private int index;
-
- /**
- * Constructor simply holds the specification streang ahead of the {@link #parse()} operation.
- *
- * @param spec format specifier to parse (e.g. "<+12.3f")
- */
- public InternalFormatSpecParser(String spec) {
- this.spec = spec;
- this.index = 0;
- }
-
- private static boolean isAlign(char c) {
- switch (c) {
- case '<':
- case '>':
- case '=':
- case '^':
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Parse the specification with which this object was initialised into an
- * {@link InternalFormatSpec}, which is an object encapsulating the format for use by formatting
- * methods. This parser deals only with the format specifiers themselves, as accepted by the
- * <code>__format__</code> method of a type, or the <code>format()</code> built-in, not format
- * strings in general as accepted by <code>str.format()</code>. A typical idiom is:
- *
- * <pre>
- * InternalFormatSpec spec = new InternalFormatSpecParser(specString).parse();
- * </pre>
- *
- * @return the <code>InternalFormatSpec</code> equivalent to the constructor argument
- */
- /*
- * This method is the equivalent of CPython's parse_internal_render_format_spec() in
- * ~/Objects/stringlib/formatter.h.
- */
- // XXX Better encapsulated as a constructor of InternalFormatSpec?
- public InternalFormatSpec parse() {
- InternalFormatSpec result = new InternalFormatSpec();
- if (spec.length() >= 1 && isAlign(spec.charAt(0))) {
- result.align = spec.charAt(index);
- index++;
- } else if (spec.length() >= 2 && isAlign(spec.charAt(1))) {
- result.fill_char = spec.charAt(0);
- result.align = spec.charAt(1);
- index += 2;
- }
- if (isAt("+- ")) {
- result.sign = spec.charAt(index);
- index++;
- }
- if (isAt("#")) {
- result.alternate = true;
- index++;
- }
- if (result.fill_char == '\0' && isAt("0")) {
- result.fill_char = '0';
- if (result.align == '\0') {
- result.align = '=';
- }
- index++;
- }
- result.width = getInteger();
- if (isAt(",")) {
- result.thousands_separators = true;
- index++;
- }
- if (isAt(".")) {
- index++;
- result.precision = getInteger();
- if (result.precision == -1) {
- throw new IllegalArgumentException("Format specifier missing precision");
- }
- }
- if (index < spec.length()) {
- result.type = spec.charAt(index);
- if (index + 1 != spec.length()) {
- throw new IllegalArgumentException("Invalid conversion specification");
- }
- }
- if (result.thousands_separators && "defgEG%F\0".indexOf(result.type) == -1) {
- throw new IllegalArgumentException("Cannot specify ',' with '" + result.type + "'.");
- }
- return result;
- }
-
- private int getInteger() {
- int value = 0;
- boolean empty = true;
- while (index < spec.length() && spec.charAt(index) >= '0' && spec.charAt(index) <= '9') {
- value = value * 10 + spec.charAt(index) - '0';
- index++;
- empty = false;
- }
- if (empty) {
- return -1;
- }
- return value;
- }
-
- private boolean isAt(String chars) {
- return index < spec.length() && chars.indexOf(spec.charAt(index)) >= 0;
- }
-}
diff --git a/tests/java/org/python/core/StringFormatTest.java b/tests/java/org/python/core/StringFormatTest.java
--- a/tests/java/org/python/core/StringFormatTest.java
+++ b/tests/java/org/python/core/StringFormatTest.java
@@ -7,10 +7,9 @@
import org.python.core.stringlib.FieldNameIterator;
import org.python.core.stringlib.IntegerFormatter;
import org.python.core.stringlib.InternalFormat;
-import org.python.core.stringlib.InternalFormatSpec;
-import org.python.core.stringlib.InternalFormatSpecParser;
import org.python.core.stringlib.MarkupIterator;
import org.python.core.stringlib.TextFormatter;
+import org.python.core.stringlib.InternalFormat.Spec;
import org.python.util.PythonInterpreter;
/**
@@ -22,33 +21,38 @@
PythonInterpreter interp = new PythonInterpreter();
public void testInternalFormatSpec() {
- InternalFormatSpec spec = new InternalFormatSpecParser("x").parse();
+ InternalFormat.Spec spec;
+ spec = InternalFormat.fromText("x");
+ assertFalse(Spec.specified(spec.align));
+ assertFalse(Spec.specified(spec.fill));
+ assertFalse(Spec.specified(spec.width));
+ assertFalse(Spec.specified(spec.precision));
assertEquals('x', spec.type);
- spec = new InternalFormatSpecParser("<x").parse();
+ spec = InternalFormat.fromText("<x");
assertEquals('<', spec.align);
assertEquals('x', spec.type);
- spec = new InternalFormatSpecParser("~<x").parse();
- assertEquals('~', spec.fill_char);
+ spec = InternalFormat.fromText("~<x");
+ assertEquals('~', spec.fill);
assertEquals('<', spec.align);
assertEquals('x', spec.type);
- spec = new InternalFormatSpecParser("+x").parse();
+ spec = InternalFormat.fromText("+x");
assertEquals('+', spec.sign);
assertEquals('x', spec.type);
- spec = new InternalFormatSpecParser("#x").parse();
+ spec = InternalFormat.fromText("#x");
assertEquals(true, spec.alternate);
- spec = new InternalFormatSpecParser("0x").parse();
+ spec = InternalFormat.fromText("0x");
assertEquals('=', spec.align);
- assertEquals('0', spec.fill_char);
+ assertEquals('0', spec.fill);
- spec = new InternalFormatSpecParser("123x").parse();
+ spec = InternalFormat.fromText("123x");
assertEquals(123, spec.width);
- spec = new InternalFormatSpecParser("123.456x").parse();
+ spec = InternalFormat.fromText("123.456x");
assertEquals(123, spec.width);
assertEquals(456, spec.precision);
@@ -56,16 +60,17 @@
assertParseError("123xx", "Invalid conversion specification");
- spec = new InternalFormatSpecParser("").parse();
- assertEquals(0, spec.type);
+ spec = InternalFormat.fromText("");
+ assertEquals(Spec.NONE, spec.type);
}
private void assertParseError(String spec, String expected) {
String error = null;
try {
- new InternalFormatSpecParser(spec).parse();
- } catch (IllegalArgumentException e) {
- error = e.getMessage();
+ InternalFormat.fromText(spec);
+ } catch (PyException e) {
+ assertEquals(Py.ValueError, e.type);
+ error = e.value.toString();
}
assertEquals(expected, error);
}
--
Repository URL: http://hg.python.org/jython
More information about the Jython-checkins
mailing list