Skip to content

Commit d89ca3c

Browse files
committed
add spitlines
1 parent 434985d commit d89ca3c

File tree

3 files changed

+90
-3
lines changed

3 files changed

+90
-3
lines changed

tests/snippets/bytes.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,14 +541,25 @@
541541
assert b"123456789".partition(b"45") == (b"123", b"45", b"6789")
542542
assert b"14523456789".partition(b"45") == (b"1", b"45", b"23456789")
543543
a = b"14523456789".partition(bytearray(b"45"))
544-
assert isinstance(a[1], bytearray)
544+
assert isinstance(a[1], bytearray)
545545
a = b"14523456789".partition(memoryview(b"45"))
546546
assert isinstance(a[1], memoryview)
547547

548548
# partition
549549
assert b"123456789".rpartition(b"45") == (b"123", b"45", b"6789")
550550
assert b"14523456789".rpartition(b"45") == (b"14523", b"45", b"6789")
551551
a = b"14523456789".rpartition(bytearray(b"45"))
552-
assert isinstance(a[1], bytearray)
552+
assert isinstance(a[1], bytearray)
553553
a = b"14523456789".rpartition(memoryview(b"45"))
554554
assert isinstance(a[1], memoryview)
555+
556+
# splitlines
557+
assert b"ab c\n\nde fg\rkl\r\n".splitlines() == [b"ab c", b"", b"de fg", b"kl"]
558+
assert b"ab c\n\nde fg\rkl\r\n".splitlines(keepends=True) == [
559+
b"ab c\n",
560+
b"\n",
561+
b"de fg\r",
562+
b"kl\r\n",
563+
]
564+
assert b"".splitlines() == []
565+
assert b"One line\n".splitlines() == [b"One line"]

vm/src/obj/objbyteinner.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,22 @@ impl ByteInnerExpandtabsOptions {
308308
}
309309
}
310310

311+
#[derive(FromArgs)]
312+
pub struct ByteInnerSplitlinesOptions {
313+
#[pyarg(positional_or_keyword, optional = true)]
314+
keepends: OptionalArg<PyObjectRef>,
315+
}
316+
317+
impl ByteInnerSplitlinesOptions {
318+
pub fn get_value(self, vm: &VirtualMachine) -> PyResult<bool> {
319+
if let OptionalArg::Present(value) = self.keepends {
320+
Ok(bool::try_from_object(vm, value)?)
321+
} else {
322+
Ok(false)
323+
}
324+
}
325+
}
326+
311327
impl PyByteInner {
312328
pub fn repr(&self) -> PyResult<String> {
313329
let mut res = String::with_capacity(self.elements.len());
@@ -881,6 +897,54 @@ impl PyByteInner {
881897

882898
res
883899
}
900+
901+
pub fn splitlines(
902+
&self,
903+
options: ByteInnerSplitlinesOptions,
904+
vm: &VirtualMachine,
905+
) -> PyResult<Vec<&[u8]>> {
906+
let keepends = options.get_value(vm)?;
907+
908+
let mut res = vec![];
909+
910+
if self.elements.is_empty() {
911+
return Ok(vec![]);
912+
}
913+
914+
let mut prev_index = 0;
915+
let mut index = 0;
916+
let keep = if keepends { 1 } else { 0 };
917+
let slice = &self.elements;
918+
919+
while index < slice.len() {
920+
match slice[index] {
921+
b'\n' => {
922+
res.push(&slice[prev_index..index + keep]);
923+
index += 1;
924+
prev_index = index;
925+
}
926+
b'\r' => {
927+
if index + 2 <= slice.len() && slice[index + 1] == b'\n' {
928+
res.push(&slice[prev_index..index + keep + keep]);
929+
index += 2;
930+
} else {
931+
res.push(&slice[prev_index..index + keep]);
932+
index += 1;
933+
}
934+
prev_index = index;
935+
}
936+
_x => {
937+
if index == slice.len() - 1 {
938+
res.push(&slice[prev_index..=index]);
939+
break;
940+
}
941+
index += 1
942+
}
943+
}
944+
}
945+
946+
Ok(res)
947+
}
884948
}
885949

886950
pub fn try_as_byte(obj: &PyObjectRef) -> Option<Vec<u8>> {

vm/src/obj/objbytes.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ use crate::pyobject::{PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, Py
1313

1414
use super::objbyteinner::{
1515
ByteInnerExpandtabsOptions, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
16-
ByteInnerPosition, ByteInnerSplitOptions, ByteInnerTranslateOptions, PyByteInner,
16+
ByteInnerPosition, ByteInnerSplitOptions, ByteInnerSplitlinesOptions,
17+
ByteInnerTranslateOptions, PyByteInner,
1718
};
1819
use super::objiter;
1920

@@ -379,6 +380,17 @@ impl PyBytesRef {
379380
fn expandtabs(self, options: ByteInnerExpandtabsOptions, vm: &VirtualMachine) -> PyResult {
380381
Ok(vm.ctx.new_bytes(self.inner.expandtabs(options)))
381382
}
383+
384+
#[pymethod(name = "splitlines")]
385+
fn splitlines(self, options: ByteInnerSplitlinesOptions, vm: &VirtualMachine) -> PyResult {
386+
let as_bytes = self
387+
.inner
388+
.splitlines(options, vm)?
389+
.iter()
390+
.map(|x| vm.ctx.new_bytes(x.to_vec()))
391+
.collect::<Vec<PyObjectRef>>();
392+
Ok(vm.ctx.new_list(as_bytes))
393+
}
382394
}
383395

384396
#[derive(Debug)]

0 commit comments

Comments
 (0)