@@ -1343,25 +1343,17 @@ class BufferedWriter
13431343 });
13441344 }
13451345
1346- PyResult<PyObject *> raw_write ()
1347- {
1348- std::array<char , BUFSIZ > to_write;
1349-
1350- while (true ) {
1351- // very innefficient - we shouldn't be getting data from buffer, create an intermediate
1352- // bytes buffer copy just to then get a view of it.
1353- auto written = buffer->sgetn (to_write.data (), BUFSIZ );
1354- if (written <= 0 ) { break ; }
1355- auto *raw_bytes = bit_cast<std::byte *>(to_write.data ());
1356- auto bytes = PyBytes::create (Bytes{ .b = { raw_bytes, raw_bytes + written } });
1357- auto memobj = PyMemoryView::create (bytes.unwrap ());
1358- if (memobj.is_err ()) { return memobj; }
1359- return raw->get_method (PyString::create (" write" ).unwrap ())
1360- .and_then ([memobj](PyObject *write) {
1361- return write->call (PyTuple::create (memobj.unwrap ()).unwrap (), nullptr );
1362- });
1363- }
1364- return Ok (py_none ());
1346+ PyResult<PyObject *> raw_write (const char *data, size_t len)
1347+ {
1348+ auto *raw_bytes = bit_cast<std::byte *>(data);
1349+ auto bytes = PyBytes::create (Bytes{ .b = { raw_bytes, raw_bytes + len } });
1350+ auto memobj = PyMemoryView::create (bytes.unwrap ());
1351+ if (memobj.is_err ()) { return memobj; }
1352+ return raw->get_method (PyString::create (" write" ).unwrap ())
1353+ .and_then ([memobj](PyObject *write) {
1354+ return write->call (PyTuple::create (memobj.unwrap ()).unwrap (), nullptr );
1355+ })
1356+ .and_then ([](auto ) { return Ok (py_none ()); });
13651357 }
13661358
13671359 PyResult<PyObject *> write (PyTuple *args, PyDict *kwargs)
@@ -1393,24 +1385,29 @@ class BufferedWriter
13931385 }
13941386
13951387 // flush our internal buffer to raw
1396- if (auto r = raw_write (); r.is_err ()) { return r; }
1388+ if (auto r = flush (); r.is_err ()) { return r; }
13971389
13981390 // TODO: this currently writes to internal buffer and then immediately makes a copy in
13991391 // write_raw. This is because streambuf doesn't tell us how much capacity it has left, so we
14001392 // just give it as much as we can each time
14011393 ssize_t remaining = buffer.len ;
14021394 char *start = static_cast <char *>(buffer.buf ->get_buffer ());
1403- while (remaining > written) {
1404- const auto count = this ->buffer ->sputn (start + written, buffer.len );
1395+ // TODO: use a buffer that actually tells us how much we can write to it, rather than
1396+ // hardcode 4096
1397+ while (remaining > 4096 ) {
14051398 // flush our internal buffer to raw
1406- if (auto r = raw_write (); r.is_err ()) { return r; }
1399+ auto r = raw_write (start + written, remaining);
1400+ if (r.is_err ()) { return r; }
1401+ ASSERT (as<PyInteger>(r.unwrap ()));
1402+ const auto count = as<PyInteger>(r.unwrap ())->as_size_t ();
14071403 written += count;
14081404 remaining -= count;
14091405 }
14101406
1411- // now we are done copying everything from buffer to our internal buffer
1412- // and we also have written it all out to raw (since we don't look up internal buffer
1413- // capacity before write)
1407+ // put the rest in our buffer. Assumes that we can write 4096 bytes
1408+ const auto count = this ->buffer ->sputn (start + written, remaining);
1409+ ASSERT (remaining - count == 0 );
1410+
14141411 return PyInteger::create (written);
14151412 }
14161413
@@ -1449,11 +1446,27 @@ template<> PyResult<PyObject *> Buffered<BufferedWriter>::flush_and_rewind()
14491446
14501447PyResult<PyObject *> BufferedWriter::flush ()
14511448{
1452- if (auto err = check_initialized (); err.is_err ()) return Err (err.unwrap_err ());
1453- if (auto err = Buffered<BufferedWriter>::check_closed (" " ); err.is_err ()) {
1454- return Err (err.unwrap_err ());
1449+ if (!writable_) { return Ok (py_none ()); }
1450+ std::array<char , BUFSIZ > to_write;
1451+
1452+ while (true ) {
1453+ // very innefficient - we shouldn't be getting data from buffer, create an intermediate
1454+ // bytes buffer copy just to then get a view of it.
1455+ auto written = buffer->sgetn (to_write.data (), BUFSIZ );
1456+ if (written <= 0 ) { break ; }
1457+ auto *raw_bytes = bit_cast<std::byte *>(to_write.data ());
1458+ auto bytes = PyBytes::create (Bytes{ .b = { raw_bytes, raw_bytes + written } });
1459+ auto memobj = PyMemoryView::create (bytes.unwrap ());
1460+ if (memobj.is_err ()) { return memobj; }
1461+ if (auto r = raw->get_method (PyString::create (" write" ).unwrap ())
1462+ .and_then ([memobj](PyObject *write) {
1463+ return write->call (PyTuple::create (memobj.unwrap ()).unwrap (), nullptr );
1464+ });
1465+ r.is_err ()) {
1466+ return r;
1467+ }
14551468 }
1456- return raw_write (). and_then ([]( auto ) { return Ok (py_none ()); } );
1469+ return Ok (py_none ());
14571470}
14581471
14591472template <> BufferedReader *as (PyObject *obj)
@@ -2166,7 +2179,7 @@ class FileIO : public RawIOBase
21662179 .def (" readall" , &FileIO::readall)
21672180 .def (" write" , &FileIO::write)
21682181 .def (" close" , &FileIO::close)
2169- .def (" close " , &FileIO::flush)
2182+ .def (" flush " , &FileIO::flush)
21702183 .finalize ();
21712184 }
21722185 module ->add_symbol (PyString::create (" FileIO" ).unwrap (), s_io_fileio);
0 commit comments