[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