Skip to content

Commit a218b3d

Browse files
committed
fix bytearray.startswith tuple to also work for subclasses or native tuples by going the generic route
1 parent 740e9c4 commit a218b3d

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_bytes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,9 +442,17 @@ def test_startswith():
442442
assert b.startswith(b"h")
443443
assert not b.startswith(b"hellow")
444444
assert not b.startswith(b"ha")
445+
445446
assert b.startswith((b"hellow", b"he"))
446447
assert not b.startswith((b"hellow", b"ha"))
447448

449+
try:
450+
assert b.startswith(("hel", "hello"))
451+
except TypeError:
452+
assert True
453+
else:
454+
assert False
455+
448456

449457
def test_endswith():
450458
b = b'hello'

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,18 @@
6767
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
6868
import com.oracle.graal.python.nodes.SpecialMethodNames;
6969
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
70+
import com.oracle.graal.python.nodes.control.GetIteratorExpressionNode.GetIteratorNode;
71+
import com.oracle.graal.python.nodes.control.GetNextNode;
7072
import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
7173
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
7274
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
7375
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
7476
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
7577
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
7678
import com.oracle.graal.python.nodes.object.GetLazyClassNode;
79+
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
7780
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
81+
import com.oracle.graal.python.runtime.exception.PException;
7882
import com.oracle.graal.python.runtime.sequence.PSequence;
7983
import com.oracle.graal.python.runtime.sequence.storage.ByteSequenceStorage;
8084
import com.oracle.graal.python.runtime.sequence.storage.IntSequenceStorage;
@@ -478,15 +482,28 @@ abstract static class StartsWithNode extends PythonBuiltinNode {
478482
@Child private SequenceStorageNodes.LenNode lenNode;
479483

480484
@Specialization
481-
boolean startswith(PByteArray self, PTuple prefixes, @SuppressWarnings("unused") PNone start, @SuppressWarnings("unused") PNone end,
482-
@Cached("create()") BytesNodes.FindNode findNode) {
483-
for (Object arrayObj : prefixes.getArray()) {
484-
PIBytesLike array = (PIBytesLike) arrayObj;
485-
if (startswith(self, array, start, end, findNode)) {
486-
return true;
485+
boolean startswith(VirtualFrame frame, PByteArray self, PTuple prefixes, @SuppressWarnings("unused") PNone start, @SuppressWarnings("unused") PNone end,
486+
@Cached GetIteratorNode getIteratorNode,
487+
@Cached IsBuiltinClassProfile errorProfile,
488+
@Cached GetNextNode getNextNode,
489+
@Cached BytesNodes.FindNode findNode) {
490+
Object iterator = getIteratorNode.executeWith(frame, prefixes);
491+
while (true) {
492+
try {
493+
Object arrayObj = getNextNode.execute(frame, iterator);
494+
if (arrayObj instanceof PIBytesLike) {
495+
PIBytesLike array = (PIBytesLike) arrayObj;
496+
if (startswith(self, array, start, end, findNode)) {
497+
return true;
498+
}
499+
} else {
500+
throw raise(PythonBuiltinClassType.TypeError, "a bytes-like object is required, not '%p'", arrayObj);
501+
}
502+
} catch (PException e) {
503+
e.expectStopIteration(errorProfile);
504+
return false;
487505
}
488506
}
489-
return false;
490507
}
491508

492509
@Specialization

0 commit comments

Comments
 (0)