Repository: bitcoin/bitcoin
File: src/util/string.cpp (C++)

Code before:
LineReader::LineReader(std::span<const std::byte> buffer, size_t max_read)
    : start(buffer.begin()), end(buffer.end()), max_read(max_read), it(buffer.begin()) {}

std::optional<std::string> LineReader::ReadLine()
{
    if (it == end) {
        return std::nullopt;
    }

    auto line_start = it;
    size_t count = 0;
    while (it != end) {
        // Read a character from the incoming buffer and increment the iterator
        auto c = static_cast<char>(*it);
        ++it;
        ++count;
        // If the character we just consumed was \n, the line is terminated
        if (c == '\n') break;
        // If we are at the end of the incoming buffer, the line is terminated
        if (it == end) break;
        // If the character we just consumed gives us a line length greater
        // than max_read, and we are not at the end of the line (or buffer) yet,
        // that means the line we are currently reading is too long, and we throw.
        if (count > max_read) throw std::runtime_error("max_read exceeded by LineReader");
    }
    const std::string_view untrimmed_line(reinterpret_cast<const char *>(std::to_address(line_start)), count);
    const std::string_view line = TrimStringView(untrimmed_line); // delete trailing \r and/or \n
    return std::string(line);
}

// Ignores max_read but won't overflow
std::string LineReader::ReadLength(size_t len)
{
    if (len == 0) return "";
    if (Left() < len) throw std::runtime_error("Not enough data in buffer");
    std::string out(reinterpret_cast<const char*>(std::to_address(it)), len);
    it += len;
    return out;
}

size_t LineReader::Left() const
{
    return std::distance(it, end);
}
} // namespace util


Review comment (suggestion):
```suggestion
    const std::string_view untrimmed_line(reinterpret_cast<const char*>(std::to_address(line_start)), count);
```

Code after:
LineReader::LineReader(std::span<const std::byte> buffer, size_t max_line_length)
    : start(buffer.begin()), end(buffer.end()), max_line_length(max_line_length), it(buffer.begin()) {}

std::optional<std::string> LineReader::ReadLine()
{
    if (it == end) {
        return std::nullopt;
    }

    auto line_start = it;
    size_t count = 0;
    while (it != end) {
        // Read a character from the incoming buffer and increment the iterator
        auto c = static_cast<char>(*it);
        ++it;
        ++count;
        // If the character we just consumed was \n, the line is terminated.
        // The \n itself does not count against max_line_length.
        if (c == '\n') {
            const std::string_view untrimmed_line(reinterpret_cast<const char*>(std::to_address(line_start)), count);
            const std::string_view line = TrimStringView(untrimmed_line); // delete leading and trailing whitespace including \r and \n
            return std::string(line);
        }
        // If the character we just consumed gives us a line length greater
        // than max_line_length, and we are not at the end of the line (or buffer) yet,
        // that means the line we are currently reading is too long, and we throw.
        if (count > max_line_length) {
            // Reset iterator
            it = line_start;
            throw std::runtime_error("max_line_length exceeded by LineReader");
        }
    }
    // End of buffer reached without finding a \n or exceeding max_line_length.
    // Reset the iterator so the rest of the buffer can be read granularly
    // with ReadLength() and return null to indicate a line was not found.
    it = line_start;
    return std::nullopt;
}

// Ignores max_line_length but won't overflow
std::string LineReader::ReadLength(size_t len)
{
    if (len == 0) return "";
    if (Remaining() < len) throw std::runtime_error("Not enough data in buffer");
    std::string out(reinterpret_cast<const char*>(std::to_address(it)), len);
    it += len;
    return out;
}

size_t LineReader::Remaining() const
{