Branch data Line data Source code
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 : 882 : void ReplaceAll(std::string& in_out, std::string_view search, std::string_view substitute)
15 : : {
16 [ + - ]: 882 : if (search.empty()) return;
17 : 882 : auto pos{in_out.find(search)};
18 [ + + ]: 882 : if (pos == std::string::npos) return;
19 : :
20 : : // Build separately because repeated std::string::replace() calls move the remaining suffix when sizes differ
21 [ - + ]: 46 : std::string result;
22 [ - + + - ]: 46 : result.reserve(in_out.size());
23 : : std::string::size_type start{0};
24 [ + + ]: 315 : for (; pos != std::string::npos; pos = in_out.find(search, start)) {
25 [ + - + - ]: 269 : result.append(in_out, start, pos - start).append(substitute);
26 : 269 : start = pos + search.size();
27 : : }
28 [ + - ]: 46 : result.append(in_out, start);
29 : 46 : in_out.swap(result);
30 : 46 : }
31 : :
32 : 146 : LineReader::LineReader(std::string_view str, size_t max_line_length)
33 : 146 : : m_str{str}, m_max_line_length{max_line_length}, m_it{str.begin()} {}
34 : :
35 : 2738 : std::optional<std::string_view> LineReader::ReadLine()
36 : : {
37 [ + + ]: 2738 : if (m_it == m_str.end()) {
38 : 7 : return std::nullopt;
39 : : }
40 : :
41 : : const auto line_start = m_it;
42 [ + + ]: 42329 : while (m_it != m_str.end()) {
43 : : // Read a character from the incoming buffer and increment the iterator
44 : 42303 : const bool new_line{*m_it == '\n'};
45 : 42303 : ++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 [ + + ]: 42303 : if (new_line) {
49 [ + + ]: 2705 : std::string_view line{line_start, m_it - 1};
50 [ + + + + ]: 2705 : if (!line.empty() && line.back() == '\r')
51 : 383 : line.remove_suffix(1);
52 : 2705 : return line;
53 : : }
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 [ + - ]: 39598 : if (static_cast<size_t>(std::distance(line_start, m_it)) > m_max_line_length) {
58 : : // Reset iterator
59 : 0 : m_it = line_start;
60 [ # # ]: 0 : throw std::runtime_error("max_line_length exceeded by LineReader");
61 : : }
62 : : }
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 : 26 : m_it = line_start;
67 : 26 : return std::nullopt;
68 : : }
69 : :
70 : : // Ignores max_line_length but won't overflow
71 : 2 : std::string_view LineReader::ReadLength(size_t len)
72 : : {
73 [ + + ]: 2 : if (len == 0) return {};
74 [ - + - - ]: 1 : if (Remaining() < len) throw std::runtime_error("Not enough data in buffer");
75 : 1 : std::string_view out(std::to_address(m_it), len);
76 : 1 : m_it += len;
77 : 1 : return out;
78 : : }
79 : :
80 : 3 : size_t LineReader::Remaining() const
81 : : {
82 : 3 : return std::distance(m_it, m_str.end());
83 : : }
84 : :
85 : 2734 : size_t LineReader::Consumed() const
86 : : {
87 : 2734 : return std::distance(m_str.begin(), m_it);
88 : : }
89 : : } // namespace util
|