Coverage Report

Created: 2026-09-14 20:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/util/string.cpp
Line
Count
Source
1
// Copyright (c) 2019-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#include <util/string.h>
6
7
#include <iterator>
8
#include <memory>
9
#include <stdexcept>
10
#include <string>
11
#include <string_view>
12
13
namespace util {
14
void ReplaceAll(std::string& in_out, std::string_view search, std::string_view substitute)
15
280
{
16
280
    if (search.empty()) return;
17
278
    auto pos{in_out.find(search)};
18
278
    if (pos == std::string::npos) return;
19
20
    // Build separately because repeated std::string::replace() calls move the remaining suffix when sizes differ
21
276
    std::string result;
22
276
    result.reserve(in_out.size());
23
276
    std::string::size_type start{0};
24
561
    for (; pos != std::string::npos; pos = in_out.find(search, start)) {
25
285
        result.append(in_out, start, pos - start).append(substitute);
26
285
        start = pos + search.size();
27
285
    }
28
276
    result.append(in_out, start);
29
276
    in_out.swap(result);
30
276
}
31
32
LineReader::LineReader(std::string_view str, size_t max_line_length)
33
267k
    : m_str{str}, m_max_line_length{max_line_length}, m_it{str.begin()} {}
34
35
std::optional<std::string_view> LineReader::ReadLine()
36
1.49M
{
37
1.49M
    if (m_it == m_str.end()) {
38
180
        return std::nullopt;
39
180
    }
40
41
1.49M
    const auto line_start = m_it;
42
53.8M
    while (m_it != m_str.end()) {
43
        // Read a character from the incoming buffer and increment the iterator
44
53.8M
        const bool new_line{*m_it == '\n'};
45
53.8M
        ++m_it;
46
        // If the character we just consumed was \n, the line is terminated.
47
        // The \n itself does not count against max_line_length.
48
53.8M
        if (new_line) {
49
1.49M
            std::string_view line{line_start, m_it - 1};
50
1.49M
            if (!line.empty() && line.back() == '\r')
51
1.49M
                line.remove_suffix(1);
52
1.49M
            return line;
53
1.49M
        }
54
        // If the character we just consumed gives us a line length greater
55
        // than max_line_length, and we are not at the end of the line (or buffer) yet,
56
        // that means the line we are currently reading is too long, and we throw.
57
52.3M
        if (static_cast<size_t>(std::distance(line_start, m_it)) > m_max_line_length) {
58
            // Reset iterator
59
7
            m_it = line_start;
60
7
            throw std::runtime_error("max_line_length exceeded by LineReader");
61
7
        }
62
52.3M
    }
63
    // End of buffer reached without finding a \n or exceeding max_line_length.
64
    // Reset the iterator so the rest of the buffer can be read granularly
65
    // with ReadLength() and return null to indicate a line was not found.
66
52
    m_it = line_start;
67
52
    return std::nullopt;
68
1.49M
}
69
70
// Ignores max_line_length but won't overflow
71
std::string_view LineReader::ReadLength(size_t len)
72
265k
{
73
265k
    if (len == 0) return {};
74
229k
    if (Remaining() < len) throw std::runtime_error("Not enough data in buffer");
75
229k
    std::string_view out(std::to_address(m_it), len);
76
229k
    m_it += len;
77
229k
    return out;
78
229k
}
79
80
size_t LineReader::Remaining() const
81
495k
{
82
495k
    return std::distance(m_it, m_str.end());
83
495k
}
84
85
size_t LineReader::Consumed() const
86
1.94M
{
87
1.94M
    return std::distance(m_str.begin(), m_it);
88
1.94M
}
89
} // namespace util