Skip to content

Commit b11a82f

Browse files
committed
More review comments
1 parent 6c8954a commit b11a82f

1 file changed

Lines changed: 40 additions & 17 deletions

File tree

src/runtime/modules/IOModule.cpp

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2954,6 +2954,10 @@ class TextIOWrapper : public TextIOBase
29542954

29552955
size_t m_chunk_size{ 8192 };
29562956

2957+
// line terminators recognised by readline; universal newlines for now
2958+
// TODO: derive the set from the newline constructor argument
2959+
std::vector<std::string> m_line_delimiters{ "\r\n", "\r", "\n" };
2960+
29572961
TextIOWrapper(PyType *type) : TextIOBase(type) {}
29582962

29592963
public:
@@ -3128,27 +3132,38 @@ class TextIOWrapper : public TextIOBase
31283132
{
31293133
if (auto result = writeflush(); result.is_err()) { return Err(result.unwrap_err()); }
31303134

3131-
// Lines in the input can end in \'\\n\', \'\\r\', or \'\\r\\n\'
3132-
auto is_line_end = [](std::string_view remaining) {
3133-
if (remaining.starts_with("\r\n")) { return 2; }
3134-
if (remaining.starts_with("\n") || remaining.starts_with("\r")) { return 1; }
3135-
return 0;
3135+
// length of the longest line delimiter at the start of text, 0 if none
3136+
auto match_delimiter = [this](std::string_view text) -> size_t {
3137+
size_t longest = 0;
3138+
for (const auto &delimiter : m_line_delimiters) {
3139+
if (delimiter.size() > longest && text.starts_with(delimiter)) {
3140+
longest = delimiter.size();
3141+
}
3142+
}
3143+
return longest;
3144+
};
3145+
// text runs to the end of the available input; a proper prefix of a
3146+
// delimiter cannot be classified until more input arrives
3147+
auto is_delimiter_prefix = [this](std::string_view text) {
3148+
for (const auto &delimiter : m_line_delimiters) {
3149+
if (delimiter.size() > text.size()
3150+
&& std::string_view{ delimiter }.starts_with(text)) {
3151+
return true;
3152+
}
3153+
}
3154+
return false;
31363155
};
31373156
std::string line;
31383157
bool found_nl = false;
3158+
bool eof = false;
3159+
bool need_more = false;
31393160
while (!found_nl && line.size() < limit) {
3140-
if (!m_buffer_bytes.has_value() || m_buffer_bytes->b.empty()) {
3161+
if (need_more || !m_buffer_bytes.has_value() || m_buffer_bytes->b.empty()) {
3162+
need_more = false;
31413163
auto chunk = read_chunk(0);
31423164
if (chunk.is_err()) { return Err(chunk.unwrap_err()); }
3143-
if (!chunk.unwrap()) { break; }
3144-
}
3145-
3146-
// a trailing '\r' may be the first byte of a "\r\n" that straddles the
3147-
// chunk boundary; read ahead so is_line_end can see the full terminator
3148-
while (m_buffer_bytes->b.back() == std::byte{ '\r' }) {
3149-
auto chunk = read_chunk(0);
3150-
if (chunk.is_err()) { return Err(chunk.unwrap_err()); }
3151-
if (!chunk.unwrap()) { break; }
3165+
eof = !chunk.unwrap();
3166+
if (eof && (!m_buffer_bytes.has_value() || m_buffer_bytes->b.empty())) { break; }
31523167
}
31533168

31543169
std::string_view remaining{ bit_cast<const char *>(m_buffer_bytes->b.data())
@@ -3161,8 +3176,16 @@ class TextIOWrapper : public TextIOBase
31613176
const size_t budget = limit - line.size();
31623177
const size_t scan_limit = std::min(budget, remaining.size());
31633178
for (; len < scan_limit; ++len) {
3164-
if (auto chars = is_line_end(remaining)) {
3165-
// the terminator may extend past the caller's limit (e.g. a
3179+
// the rest of the buffer may hold an incomplete delimiter (e.g. the
3180+
// '\r' of a "\r\n" straddling the chunk boundary); fetch more input
3181+
// before classifying it, unless the size limit would clamp the
3182+
// consumed length to the same result either way
3183+
if (!eof && len + 1 < budget && is_delimiter_prefix(remaining)) {
3184+
need_more = true;
3185+
break;
3186+
}
3187+
if (auto chars = match_delimiter(remaining)) {
3188+
// the delimiter may extend past the caller's limit (e.g. a
31663189
// "\r\n" straddling it); consume only up to the limit and
31673190
// leave the rest buffered for the next call
31683191
len = std::min(len + chars, budget);

0 commit comments

Comments
 (0)