[Jython-checkins] jython: Implement bytearray.startswith and endswith.

frank.wierzbicki jython-checkins at python.org
Wed May 30 05:17:20 CEST 2012


http://hg.python.org/jython/rev/7e26c04c05d5
changeset:   6676:7e26c04c05d5
user:        Jeff Allen <ja...py at farowl.co.uk>
date:        Sun May 27 15:47:40 2012 +0100
summary:
  Implement bytearray.startswith and endswith.
The score against test_bytes now stands at 2 failures and 61 errors.

files:
  src/org/python/core/BaseBytes.java   |  118 +++++++++++++++
  src/org/python/core/PyByteArray.java |  109 +++++++++++++
  2 files changed, 227 insertions(+), 0 deletions(-)


diff --git a/src/org/python/core/BaseBytes.java b/src/org/python/core/BaseBytes.java
--- a/src/org/python/core/BaseBytes.java
+++ b/src/org/python/core/BaseBytes.java
@@ -747,9 +747,35 @@
         public void copyTo(byte[] dest, int destPos) throws ArrayIndexOutOfBoundsException;
 
         /**
+         * Test whether this View has the given prefix, that is, that the first bytes of this View
+         * match all the bytes of the given prefix. By implication, the test returns false if there
+         * are too few bytes in this view.
+         *
+         * @param prefix pattern to match
+         * @return true if and only if this view has the given prefix
+         */
+        public boolean startswith(View prefix);
+
+        /**
+         * Test whether the slice <code>[offset:]</code> of this View has the given prefix, that is,
+         * that the bytes of this View from index <code>offset</code> match all the bytes of the
+         * give prefix. By implication, the test returns false if the offset puts the start or end
+         * of the prefix outside this view (when <code>offset&lt;0</code> or
+         * <code>offset+prefix.size()>size()</code>). Python slice semantics are <em>not</em>
+         * applied to <code>offset</code>.
+         *
+         * @param prefix pattern to match
+         * @param offset at which to start the comparison in this view
+         * @return true if and only if the slice [offset:<code>]</code> this view has the given
+         *         prefix
+         */
+        public boolean startswith(View prefix, int offset);
+
+        /**
          * The standard memoryview out of bounds message (does not refer to the underlying type).
          */
         public static final String OUT_OF_BOUNDS = "index out of bounds";
+
     }
 
     /**
@@ -805,6 +831,46 @@
                 dest[p++] = byteAt(i);
             }
         }
+
+        /**
+         * Test whether this View has the given prefix, that is, that the first bytes of this View
+         * match all the bytes of the given prefix. This class provides an implementation of
+         * {@link View#startswith(View)} that simply returns <code>startswith(prefix,0)</code>
+         */
+        @Override
+        public boolean startswith(View prefix) {
+            return startswith(prefix, 0);
+        }
+
+        /**
+         * Test whether this View has the given prefix, that is, that the first bytes of this View
+         * match all the bytes of the given prefix. This class provides an implementation of
+         * {@link View#startswith(View,int)} that loops over
+         * <code>byteAt(i+offset)==prefix.byteAt(i)</code>
+         */
+        @Override
+        public boolean startswith(View prefix, int offset) {
+            int j = offset; // index in this
+            if (j < 0) {
+                // // Start of prefix is outside this view
+                return false;
+            } else {
+                int len = prefix.size();
+                if (j + len > this.size()) {
+                    // End of prefix is outside this view
+                    return false;
+                } else {
+                    // Last resort: we have actually to look at the bytes!
+                    for (int i = 0; i < len; i++) {
+                        if (byteAt(j++) != prefix.byteAt(i)) {
+                            return false;
+                        }
+                    }
+                    return true; // They must all have matched
+                }
+            }
+        }
+
     }
 
     /**
@@ -1452,6 +1518,58 @@
     }
 
     /**
+     * Almost ready-to-expose implementation serving both Python
+     * <code>startswith( prefix [, start [, end ]] )</code> and
+     * <code>endswith( suffix [, start [, end ]] )</code>. An extra boolean argument specifies which
+     * to implement on a given call, that is, whether the target is a suffix or prefix. The target
+     * may also be a tuple of targets.
+     *
+     * @param target prefix or suffix sequence to find (of a type viewable as a byte sequence) or a
+     *            tuple of those.
+     * @param start of slice to search.
+     * @param end of slice to search.
+     * @param endswith true if we are doing endswith, false if startswith.
+     * @return true if and only if this bytearray ends with (one of) <code>target</code>.
+     */
+    protected final synchronized boolean basebytes_starts_or_endswith(PyObject target,
+                                                                      PyObject start,
+                                                                      PyObject end,
+                                                                      boolean endswith) {
+        /*
+         * This cheap trick saves us from maintaining two almost identical methods and mirrors
+         * CPython's _bytearray_tailmatch().
+         *
+         * Start with a view of the slice we are searching.
+         */
+        View v = new ViewOfBytes(this).slice(start, end);
+        int len = v.size();
+        int offset = 0;
+
+        if (target instanceof PyTuple) {
+            // target is a tuple of suffixes/prefixes and only one need match
+            for (PyObject s : ((PyTuple)target).getList()) {
+                // Error if not something we can treat as a view of bytes
+                View vt = getViewOrError(s);
+                if (endswith) {
+                    offset = len - vt.size();
+                }
+                if (v.startswith(vt, offset)) {
+                    return true;
+                }
+            }
+            return false; // None of them matched
+
+        } else {
+            // Error if target is not something we can treat as a view of bytes
+            View vt = getViewOrError(target);
+            if (endswith) {
+                offset = len - vt.size();
+            }
+            return v.startswith(vt, offset);
+        }
+    }
+
+    /**
      * Copy the bytes of a byte array to the characters of a String with no change in ordinal value.
      * This could also be described as 'latin-1' decoding of the byte array to a String.
      *
diff --git a/src/org/python/core/PyByteArray.java b/src/org/python/core/PyByteArray.java
--- a/src/org/python/core/PyByteArray.java
+++ b/src/org/python/core/PyByteArray.java
@@ -881,6 +881,60 @@
         return basebytes_count(sub, start, end);
     }
 
+    /**
+     * Implementation of Python <code>endswith(suffix)</code>.
+     *
+     * When <code>suffix</code> is of a type that may be treated as an array of bytes, return
+     * <code>true</code> if and only if this bytearray ends with the <code>suffix</code>.
+     * <code>suffix</code> can also be a tuple of suffixes to look for.
+     *
+     * @param suffix byte array to match, or object viewable as such, or a tuple of them
+     * @return true if and only if this bytearray ends with the suffix (or one of them)
+     */
+    public boolean endswith(PyObject suffix) {
+        return basebytes_starts_or_endswith(suffix, null, null, true);
+    }
+
+    /**
+     * Implementation of Python <code>endswith( suffix [, start ] )</code>.
+     *
+     * When <code>suffix</code> is of a type that may be treated as an array of bytes, return
+     * <code>true</code> if and only if this bytearray ends with the <code>suffix</code>.
+     * <code>suffix</code> can also be a tuple of suffixes to look for. With optional
+     * <code>start</code> (which may be <code>null</code> or <code>Py.None</code>), define the
+     * effective bytearray to be the slice <code>[start:]</code> of this bytearray.
+     *
+     * @param suffix byte array to match, or object viewable as such, or a tuple of them
+     * @param start of slice in this bytearray to match
+     * @return true if and only if this[start:] ends with the suffix (or one of them)
+     */
+    public boolean endswith(PyObject suffix, PyObject start) {
+        return basebytes_starts_or_endswith(suffix, start, null, true);
+    }
+
+    /**
+     * Implementation of Python <code>endswith( suffix [, start [, end ]] )</code>.
+     *
+     * When <code>suffix</code> is of a type that may be treated as an array of bytes, return
+     * <code>true</code> if and only if this bytearray ends with the <code>suffix</code>.
+     * <code>suffix</code> can also be a tuple of suffixes to look for. With optional
+     * <code>start</code> and <code>end</code> (which may be <code>null</code> or
+     * <code>Py.None</code>), define the effective bytearray to be the slice
+     * <code>[start:end]</code> of this bytearray.
+     *
+     * @param suffix byte array to match, or object viewable as such, or a tuple of them
+     * @param start of slice in this bytearray to match
+     * @param end of slice in this bytearray to match
+     * @return true if and only if this[start:end] ends with the suffix (or one of them)
+     */
+    public boolean endswith(PyObject suffix, PyObject start, PyObject end) {
+        return basebytes_starts_or_endswith(suffix, start, end, true);
+    }
+
+    @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.bytearray_endswith_doc)
+    final boolean bytearray_endswith(PyObject suffix, PyObject start, PyObject end) {
+        return basebytes_starts_or_endswith(suffix, start, end, true);
+    }
 
     /**
      * Append the elements in the argument sequence to the end of the array, equivalent to:
@@ -1200,6 +1254,61 @@
         return pos;
     }
 
+    /**
+     * Implementation of Python <code>startswith(prefix)</code>.
+     *
+     * When <code>prefix</code> is of a type that may be treated as an array of bytes, return
+     * <code>true</code> if and only if this bytearray starts with the <code>prefix</code>.
+     * <code>prefix</code> can also be a tuple of prefixes to look for.
+     *
+     * @param prefix byte array to match, or object viewable as such, or a tuple of them
+     * @return true if and only if this bytearray starts with the prefix (or one of them)
+     */
+    public boolean startswith(PyObject prefix) {
+        return basebytes_starts_or_endswith(prefix, null, null, false);
+    }
+
+    /**
+     * Implementation of Python <code>startswith( prefix [, start ] )</code>.
+     *
+     * When <code>prefix</code> is of a type that may be treated as an array of bytes, return
+     * <code>true</code> if and only if this bytearray starts with the <code>prefix</code>.
+     * <code>prefix</code> can also be a tuple of prefixes to look for. With optional
+     * <code>start</code> (which may be <code>null</code> or <code>Py.None</code>), define the
+     * effective bytearray to be the slice <code>[start:]</code> of this bytearray.
+     *
+     * @param prefix byte array to match, or object viewable as such, or a tuple of them
+     * @param start of slice in this bytearray to match
+     * @return true if and only if this[start:] starts with the prefix (or one of them)
+     */
+    public boolean startswith(PyObject prefix, PyObject start) {
+        return basebytes_starts_or_endswith(prefix, start, null, false);
+    }
+
+    /**
+     * Implementation of Python <code>startswith( prefix [, start [, end ]] )</code>.
+     *
+     * When <code>prefix</code> is of a type that may be treated as an array of bytes, return
+     * <code>true</code> if and only if this bytearray starts with the <code>prefix</code>.
+     * <code>prefix</code> can also be a tuple of prefixes to look for. With optional
+     * <code>start</code> and <code>end</code> (which may be <code>null</code> or
+     * <code>Py.None</code>), define the effective bytearray to be the slice
+     * <code>[start:end]</code> of this bytearray.
+     *
+     * @param prefix byte array to match, or object viewable as such, or a tuple of them
+     * @param start of slice in this bytearray to match
+     * @param end of slice in this bytearray to match
+     * @return true if and only if this[start:end] starts with the prefix (or one of them)
+     */
+    public boolean startswith(PyObject prefix, PyObject start, PyObject end) {
+        return basebytes_starts_or_endswith(prefix, start, end, false);
+    }
+
+    @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.bytearray_startswith_doc)
+    final boolean bytearray_startswith(PyObject prefix, PyObject start, PyObject end) {
+        return basebytes_starts_or_endswith(prefix, start, end, false);
+    }
+
 // Based on PyList and not yet properly implemented.
 //
 //    @Override

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


More information about the Jython-checkins mailing list