/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 |