/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 <regex> |
10 | | #include <stdexcept> |
11 | | #include <string> |
12 | | |
13 | | namespace util { |
14 | | void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute) |
15 | 255 | { |
16 | 255 | if (search.empty()) return; |
17 | 253 | in_out = std::regex_replace(in_out, std::regex(search), substitute); |
18 | 253 | } |
19 | | |
20 | | LineReader::LineReader(std::string_view str, size_t max_line_length) |
21 | 231k | : m_str{str}, m_max_line_length{max_line_length}, m_it{str.begin()} {} |
22 | | |
23 | | std::optional<std::string_view> LineReader::ReadLine() |
24 | 1.84M | { |
25 | 1.84M | if (m_it == m_str.end()) { |
26 | 241 | return std::nullopt; |
27 | 241 | } |
28 | | |
29 | 1.84M | const auto line_start = m_it; |
30 | 65.8M | while (m_it != m_str.end()) { |
31 | | // Read a character from the incoming buffer and increment the iterator |
32 | 65.8M | const bool new_line{*m_it == '\n'}; |
33 | 65.8M | ++m_it; |
34 | | // If the character we just consumed was \n, the line is terminated. |
35 | | // The \n itself does not count against max_line_length. |
36 | 65.8M | if (new_line) { |
37 | 1.84M | std::string_view line{line_start, m_it - 1}; |
38 | 1.84M | if (!line.empty() && line.back() == '\r') |
39 | 1.84M | line.remove_suffix(1); |
40 | 1.84M | return line; |
41 | 1.84M | } |
42 | | // If the character we just consumed gives us a line length greater |
43 | | // than max_line_length, and we are not at the end of the line (or buffer) yet, |
44 | | // that means the line we are currently reading is too long, and we throw. |
45 | 63.9M | if (static_cast<size_t>(std::distance(line_start, m_it)) > m_max_line_length) { |
46 | | // Reset iterator |
47 | 6 | m_it = line_start; |
48 | 6 | throw std::runtime_error("max_line_length exceeded by LineReader"); |
49 | 6 | } |
50 | 63.9M | } |
51 | | // End of buffer reached without finding a \n or exceeding max_line_length. |
52 | | // Reset the iterator so the rest of the buffer can be read granularly |
53 | | // with ReadLength() and return null to indicate a line was not found. |
54 | 51 | m_it = line_start; |
55 | 51 | return std::nullopt; |
56 | 1.84M | } |
57 | | |
58 | | // Ignores max_line_length but won't overflow |
59 | | std::string_view LineReader::ReadLength(size_t len) |
60 | 186k | { |
61 | 186k | if (len == 0) return {}; |
62 | 186k | if (Remaining() < len) throw std::runtime_error("Not enough data in buffer"); |
63 | 186k | std::string_view out(std::to_address(m_it), len); |
64 | 186k | m_it += len; |
65 | 186k | return out; |
66 | 186k | } |
67 | | |
68 | | size_t LineReader::Remaining() const |
69 | 419k | { |
70 | 419k | return std::distance(m_it, m_str.end()); |
71 | 419k | } |
72 | | |
73 | | size_t LineReader::Consumed() const |
74 | 1.79M | { |
75 | 1.79M | return std::distance(m_str.begin(), m_it); |
76 | 1.79M | } |
77 | | } // namespace util |