[Jython-checkins] jython: Avoid PyString range-test in concatenation and join.

jeff.allen jython-checkins at python.org
Tue Dec 2 23:11:53 CET 2014


https://hg.python.org/jython/rev/521823de34a5
changeset:   7427:521823de34a5
user:        Jeff Allen <ja.py at farowl.co.uk>
date:        Mon Dec 01 23:53:59 2014 +0000
summary:
  Avoid PyString range-test in concatenation and join.

Adds private constructor for use when we can guarantee bytes.
Apply in __add__ and join.

files:
  src/org/python/core/PyString.java |  57 +++++++++++++-----
  1 files changed, 41 insertions(+), 16 deletions(-)


diff --git a/src/org/python/core/PyString.java b/src/org/python/core/PyString.java
--- a/src/org/python/core/PyString.java
+++ b/src/org/python/core/PyString.java
@@ -39,7 +39,7 @@
 
     // for PyJavaClass.init()
     public PyString() {
-        this(TYPE, "");
+        this("", true);
     }
 
     /**
@@ -52,7 +52,7 @@
     public PyString(PyType subType, String string) {
         super(subType);
         if (string == null) {
-            throw new IllegalArgumentException("Cannot create PyString from null!");
+            throw new IllegalArgumentException("Cannot create PyString from null");
         } else if (!isBytes(string)) {
             throw new IllegalArgumentException("Cannot create PyString with non-byte value");
         }
@@ -72,6 +72,23 @@
     }
 
     /**
+     * Local-use constructor in which the client is allowed to guarantee that the
+     * <code>String</code> argument contains only characters in the byte range. We do not then
+     * range-check the characters.
+     *
+     * @param string a Java String to be wrapped (not null)
+     * @param isBytes true if the client guarantees we are dealing with bytes
+     */
+    private PyString(String string, boolean isBytes) {
+        super(TYPE);
+        if (isBytes || isBytes(string)) {
+            this.string = string;
+        } else {
+            throw new IllegalArgumentException("Cannot create PyString with non-byte value");
+        }
+    }
+
+    /**
      * Determine whether a string consists entirely of characters in the range 0 to 255. Only such
      * characters are allowed in the <code>PyString</code> (<code>str</code>) type, when it is not a
      * {@link PyUnicode}.
@@ -228,7 +245,7 @@
         if (getClass() == PyString.class) {
             return this;
         }
-        return new PyString(getString());
+        return new PyString(getString(), true);
     }
 
     @Override
@@ -785,6 +802,18 @@
      * <b>not</b> a <code>unicode</code>.
      *
      * @param obj to coerce to a String
+     * @return coerced value or <code>null</code> if it can't be (including <code>unicode</code>)
+     */
+    private static String asStringOrNull(PyObject obj) {
+        return (obj instanceof PyUnicode) ? null : asUTF16StringOrNull(obj);
+    }
+
+    /**
+     * Return a String equivalent to the argument. This is a helper function to those methods that
+     * accept any byte array type (any object that supports a one-dimensional byte buffer), but
+     * <b>not</b> a <code>unicode</code>.
+     *
+     * @param obj to coerce to a String
      * @return coerced value
      * @throws PyException if the coercion fails (including <code>unicode</code>)
      */
@@ -917,21 +946,17 @@
 
     @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.str___add___doc)
     final PyObject str___add__(PyObject other) {
-
-        if (other instanceof PyUnicode) {
+        // Expect other to be some kind of byte-like object.
+        String otherStr = asStringOrNull(other);
+        if (otherStr != null) {
+            // Yes it is: concatenate as strings, which are guaranteed byte-like.
+            return new PyString(getString().concat(otherStr), true);
+        } else if (other instanceof PyUnicode) {
             // Convert self to PyUnicode and escalate the problem
             return decode().__add__(other);
-
         } else {
-            // Some kind of object with the buffer API
-            String otherStr = asUTF16StringOrNull(other);
-            if (otherStr == null) {
-                // Allow PyObject._basic_add to pick up the pieces or raise informative error
-                return null;
-            } else {
-                // Concatenate as strings
-                return new PyString(getString().concat(otherStr));
-            }
+            // Allow PyObject._basic_add to pick up the pieces or raise informative error
+            return null;
         }
     }
 
@@ -3161,7 +3186,7 @@
             }
             buf.append(((PyString)item).getString());
         }
-        return new PyString(buf.toString());
+        return new PyString(buf.toString(), true); // Guaranteed to be byte-like
     }
 
     final PyUnicode unicodeJoin(PyObject obj) {

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list