/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 | 0 | { |
16 | 0 | if (search.empty()) return; Branch (16:9): [True: 0, False: 0]
|
17 | 0 | in_out = std::regex_replace(in_out, std::regex(search), substitute); |
18 | 0 | } |
19 | | |
20 | | LineReader::LineReader(std::span<const std::byte> buffer, size_t max_line_length) |
21 | 333k | : start(buffer.begin()), end(buffer.end()), max_line_length(max_line_length), it(buffer.begin()) {} |
22 | | |
23 | | std::optional<std::string_view> LineReader::ReadLine() |
24 | 2.01M | { |
25 | 2.01M | if (it == end) { Branch (25:9): [True: 0, False: 2.01M]
|
26 | 0 | return std::nullopt; |
27 | 0 | } |
28 | | |
29 | 2.01M | auto line_start = it; |
30 | 2.01M | size_t count = 0; |
31 | 83.9M | while (it != end) { Branch (31:12): [True: 83.9M, False: 2.44k]
|
32 | | // Read a character from the incoming buffer and increment the iterator |
33 | 83.9M | auto c = static_cast<char>(*it); |
34 | 83.9M | ++it; |
35 | 83.9M | ++count; |
36 | | // If the character we just consumed was \n, the line is terminated. |
37 | | // The \n itself does not count against max_line_length. |
38 | 83.9M | if (c == '\n') { Branch (38:13): [True: 2.01M, False: 81.9M]
|
39 | 2.01M | const std::string_view untrimmed_line(reinterpret_cast<const char*>(std::to_address(line_start)), count); |
40 | 2.01M | std::string_view line = RemoveSuffixView(untrimmed_line, "\n"); |
41 | 2.01M | return RemoveSuffixView(line, "\r"); |
42 | 2.01M | } |
43 | | // If the character we just consumed gives us a line length greater |
44 | | // than max_line_length, and we are not at the end of the line (or buffer) yet, |
45 | | // that means the line we are currently reading is too long, and we throw. |
46 | 81.9M | if (count > max_line_length) { Branch (46:13): [True: 0, False: 81.9M]
|
47 | | // Reset iterator |
48 | 0 | it = line_start; |
49 | 0 | throw std::runtime_error("max_line_length exceeded by LineReader"); |
50 | 0 | } |
51 | 81.9M | } |
52 | | // End of buffer reached without finding a \n or exceeding max_line_length. |
53 | | // Reset the iterator so the rest of the buffer can be read granularly |
54 | | // with ReadLength() and return null to indicate a line was not found. |
55 | 2.44k | it = line_start; |
56 | 2.44k | return std::nullopt; |
57 | 2.01M | } |
58 | | |
59 | | // Ignores max_line_length but won't overflow |
60 | | std::string_view LineReader::ReadLength(size_t len) |
61 | 333k | { |
62 | 333k | if (len == 0) return {}; Branch (62:9): [True: 0, False: 333k]
|
63 | 333k | if (Remaining() < len) throw std::runtime_error("Not enough data in buffer"); Branch (63:9): [True: 0, False: 333k]
|
64 | 333k | std::string_view out(reinterpret_cast<const char*>(std::to_address(it)), len); |
65 | 333k | it += len; |
66 | 333k | return out; |
67 | 333k | } |
68 | | |
69 | | size_t LineReader::Remaining() const |
70 | 668k | { |
71 | 668k | return std::distance(it, end); |
72 | 668k | } |
73 | | |
74 | | size_t LineReader::Consumed() const |
75 | 2.01M | { |
76 | 2.01M | return std::distance(start, it); |
77 | 2.01M | } |
78 | | } // namespace util |