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.h
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
#ifndef BITCOIN_UTIL_STRING_H
6
#define BITCOIN_UTIL_STRING_H
7
8
#include <algorithm>
9
#include <array>
10
#include <cstddef>
11
#include <cstdint>
12
#include <initializer_list>
13
#include <locale>
14
#include <optional>
15
#include <span>
16
#include <sstream>
17
#include <string>
18
#include <string_view>
19
#include <vector>
20
21
#include <attributes.h>
22
23
namespace util {
24
namespace detail {
25
template <unsigned num_params>
26
constexpr void CheckNumFormatSpecifiers(const char* str)
27
72
{
28
72
    unsigned count_normal{0}; // Number of "normal" specifiers, like %s
29
72
    unsigned count_pos{0};    // Max number in positional specifier, like %8$s
30
157
    for (auto it{str}; *it != '\0'; ++it) {
31
98
        if (*it != '%' || *++it == '%') continue; // Skip escaped %%
32
33
104
        auto add_arg = [&] {
34
104
            unsigned maybe_num{0};
35
172
            while ('0' <= *it && *it <= '9') {
36
68
                maybe_num *= 10;
37
68
                maybe_num += *it - '0';
38
68
                ++it;
39
68
            }
40
41
104
            if (*it == '$') {
42
56
                ++it;
43
                // Positional specifier, like %8$s
44
56
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
48
                count_pos = std::max(count_pos, maybe_num);
46
48
            } else {
47
                // Non-positional specifier, like %s
48
48
                ++count_normal;
49
48
            }
50
104
        };
void util::detail::CheckNumFormatSpecifiers<0u>(char const*)::'lambda'()::operator()() const
Line
Count
Source
33
4
        auto add_arg = [&] {
34
4
            unsigned maybe_num{0};
35
7
            while ('0' <= *it && *it <= '9') {
36
3
                maybe_num *= 10;
37
3
                maybe_num += *it - '0';
38
3
                ++it;
39
3
            }
40
41
4
            if (*it == '$') {
42
3
                ++it;
43
                // Positional specifier, like %8$s
44
3
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
1
                count_pos = std::max(count_pos, maybe_num);
46
1
            } else {
47
                // Non-positional specifier, like %s
48
1
                ++count_normal;
49
1
            }
50
4
        };
void util::detail::CheckNumFormatSpecifiers<1u>(char const*)::'lambda'()::operator()() const
Line
Count
Source
33
41
        auto add_arg = [&] {
34
41
            unsigned maybe_num{0};
35
64
            while ('0' <= *it && *it <= '9') {
36
23
                maybe_num *= 10;
37
23
                maybe_num += *it - '0';
38
23
                ++it;
39
23
            }
40
41
41
            if (*it == '$') {
42
11
                ++it;
43
                // Positional specifier, like %8$s
44
11
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
9
                count_pos = std::max(count_pos, maybe_num);
46
30
            } else {
47
                // Non-positional specifier, like %s
48
30
                ++count_normal;
49
30
            }
50
41
        };
void util::detail::CheckNumFormatSpecifiers<2u>(char const*)::'lambda'()::operator()() const
Line
Count
Source
33
29
        auto add_arg = [&] {
34
29
            unsigned maybe_num{0};
35
46
            while ('0' <= *it && *it <= '9') {
36
17
                maybe_num *= 10;
37
17
                maybe_num += *it - '0';
38
17
                ++it;
39
17
            }
40
41
29
            if (*it == '$') {
42
18
                ++it;
43
                // Positional specifier, like %8$s
44
18
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
16
                count_pos = std::max(count_pos, maybe_num);
46
16
            } else {
47
                // Non-positional specifier, like %s
48
11
                ++count_normal;
49
11
            }
50
29
        };
void util::detail::CheckNumFormatSpecifiers<129u>(char const*)::'lambda'()::operator()() const
Line
Count
Source
33
2
        auto add_arg = [&] {
34
2
            unsigned maybe_num{0};
35
6
            while ('0' <= *it && *it <= '9') {
36
4
                maybe_num *= 10;
37
4
                maybe_num += *it - '0';
38
4
                ++it;
39
4
            }
40
41
2
            if (*it == '$') {
42
2
                ++it;
43
                // Positional specifier, like %8$s
44
2
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
2
                count_pos = std::max(count_pos, maybe_num);
46
2
            } else {
47
                // Non-positional specifier, like %s
48
0
                ++count_normal;
49
0
            }
50
2
        };
void util::detail::CheckNumFormatSpecifiers<3u>(char const*)::'lambda'()::operator()() const
Line
Count
Source
33
25
        auto add_arg = [&] {
34
25
            unsigned maybe_num{0};
35
43
            while ('0' <= *it && *it <= '9') {
36
18
                maybe_num *= 10;
37
18
                maybe_num += *it - '0';
38
18
                ++it;
39
18
            }
40
41
25
            if (*it == '$') {
42
19
                ++it;
43
                // Positional specifier, like %8$s
44
19
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
17
                count_pos = std::max(count_pos, maybe_num);
46
17
            } else {
47
                // Non-positional specifier, like %s
48
6
                ++count_normal;
49
6
            }
50
25
        };
void util::detail::CheckNumFormatSpecifiers<4u>(char const*)::'lambda'()::operator()() const
Line
Count
Source
33
3
        auto add_arg = [&] {
34
3
            unsigned maybe_num{0};
35
6
            while ('0' <= *it && *it <= '9') {
36
3
                maybe_num *= 10;
37
3
                maybe_num += *it - '0';
38
3
                ++it;
39
3
            }
40
41
3
            if (*it == '$') {
42
3
                ++it;
43
                // Positional specifier, like %8$s
44
3
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
3
                count_pos = std::max(count_pos, maybe_num);
46
3
            } else {
47
                // Non-positional specifier, like %s
48
0
                ++count_normal;
49
0
            }
50
3
        };
51
52
        // Increase argument count and consume positional specifier, if present.
53
70
        add_arg();
54
55
        // Consume flags.
56
84
        while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it;
57
58
90
        auto parse_size = [&] {
59
90
            if (*it == '*') {
60
34
                ++it;
61
34
                add_arg();
62
56
            } else {
63
68
                while ('0' <= *it && *it <= '9') ++it;
64
56
            }
65
90
        };
void util::detail::CheckNumFormatSpecifiers<0u>(char const*)::'lambda0'()::operator()() const
Line
Count
Source
58
2
        auto parse_size = [&] {
59
2
            if (*it == '*') {
60
0
                ++it;
61
0
                add_arg();
62
2
            } else {
63
2
                while ('0' <= *it && *it <= '9') ++it;
64
2
            }
65
2
        };
void util::detail::CheckNumFormatSpecifiers<1u>(char const*)::'lambda0'()::operator()() const
Line
Count
Source
58
43
        auto parse_size = [&] {
59
43
            if (*it == '*') {
60
5
                ++it;
61
5
                add_arg();
62
38
            } else {
63
46
                while ('0' <= *it && *it <= '9') ++it;
64
38
            }
65
43
        };
void util::detail::CheckNumFormatSpecifiers<2u>(char const*)::'lambda0'()::operator()() const
Line
Count
Source
58
22
        auto parse_size = [&] {
59
22
            if (*it == '*') {
60
12
                ++it;
61
12
                add_arg();
62
12
            } else {
63
11
                while ('0' <= *it && *it <= '9') ++it;
64
10
            }
65
22
        };
void util::detail::CheckNumFormatSpecifiers<129u>(char const*)::'lambda0'()::operator()() const
Line
Count
Source
58
2
        auto parse_size = [&] {
59
2
            if (*it == '*') {
60
0
                ++it;
61
0
                add_arg();
62
2
            } else {
63
2
                while ('0' <= *it && *it <= '9') ++it;
64
2
            }
65
2
        };
void util::detail::CheckNumFormatSpecifiers<3u>(char const*)::'lambda0'()::operator()() const
Line
Count
Source
58
19
        auto parse_size = [&] {
59
19
            if (*it == '*') {
60
15
                ++it;
61
15
                add_arg();
62
15
            } else {
63
7
                while ('0' <= *it && *it <= '9') ++it;
64
4
            }
65
19
        };
void util::detail::CheckNumFormatSpecifiers<4u>(char const*)::'lambda0'()::operator()() const
Line
Count
Source
58
2
        auto parse_size = [&] {
59
2
            if (*it == '*') {
60
2
                ++it;
61
2
                add_arg();
62
2
            } else {
63
0
                while ('0' <= *it && *it <= '9') ++it;
64
0
            }
65
2
        };
66
67
        // Consume dynamic or static width value.
68
70
        parse_size();
69
70
        // Consume dynamic or static precision value.
71
70
        if (*it == '.') {
72
24
            ++it;
73
24
            parse_size();
74
24
        }
75
76
70
        if (*it == '\0') throw "Format specifier incorrectly terminated by end of string";
77
78
        // Length and type in "[flags][width][.precision][length]type"
79
        // is not checked. Parsing continues with the next '%'.
80
70
    }
81
59
    if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
82
54
    unsigned count{count_normal | count_pos};
83
54
    if (num_params != count) throw "Format specifier count must match the argument count!";
84
54
}
void util::detail::CheckNumFormatSpecifiers<2u>(char const*)
Line
Count
Source
27
16
{
28
16
    unsigned count_normal{0}; // Number of "normal" specifiers, like %s
29
16
    unsigned count_pos{0};    // Max number in positional specifier, like %8$s
30
35
    for (auto it{str}; *it != '\0'; ++it) {
31
22
        if (*it != '%' || *++it == '%') continue; // Skip escaped %%
32
33
17
        auto add_arg = [&] {
34
17
            unsigned maybe_num{0};
35
17
            while ('0' <= *it && *it <= '9') {
36
17
                maybe_num *= 10;
37
17
                maybe_num += *it - '0';
38
17
                ++it;
39
17
            }
40
41
17
            if (*it == '$') {
42
17
                ++it;
43
                // Positional specifier, like %8$s
44
17
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
17
                count_pos = std::max(count_pos, maybe_num);
46
17
            } else {
47
                // Non-positional specifier, like %s
48
17
                ++count_normal;
49
17
            }
50
17
        };
51
52
        // Increase argument count and consume positional specifier, if present.
53
17
        add_arg();
54
55
        // Consume flags.
56
18
        while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it;
57
58
17
        auto parse_size = [&] {
59
17
            if (*it == '*') {
60
17
                ++it;
61
17
                add_arg();
62
17
            } else {
63
17
                while ('0' <= *it && *it <= '9') ++it;
64
17
            }
65
17
        };
66
67
        // Consume dynamic or static width value.
68
17
        parse_size();
69
70
        // Consume dynamic or static precision value.
71
17
        if (*it == '.') {
72
5
            ++it;
73
5
            parse_size();
74
5
        }
75
76
17
        if (*it == '\0') throw "Format specifier incorrectly terminated by end of string";
77
78
        // Length and type in "[flags][width][.precision][length]type"
79
        // is not checked. Parsing continues with the next '%'.
80
17
    }
81
13
    if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
82
9
    unsigned count{count_normal | count_pos};
83
9
    if (num_params != count) throw "Format specifier count must match the argument count!";
84
9
}
void util::detail::CheckNumFormatSpecifiers<1u>(char const*)
Line
Count
Source
27
35
{
28
35
    unsigned count_normal{0}; // Number of "normal" specifiers, like %s
29
35
    unsigned count_pos{0};    // Max number in positional specifier, like %8$s
30
64
    for (auto it{str}; *it != '\0'; ++it) {
31
39
        if (*it != '%' || *++it == '%') continue; // Skip escaped %%
32
33
36
        auto add_arg = [&] {
34
36
            unsigned maybe_num{0};
35
36
            while ('0' <= *it && *it <= '9') {
36
36
                maybe_num *= 10;
37
36
                maybe_num += *it - '0';
38
36
                ++it;
39
36
            }
40
41
36
            if (*it == '$') {
42
36
                ++it;
43
                // Positional specifier, like %8$s
44
36
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
36
                count_pos = std::max(count_pos, maybe_num);
46
36
            } else {
47
                // Non-positional specifier, like %s
48
36
                ++count_normal;
49
36
            }
50
36
        };
51
52
        // Increase argument count and consume positional specifier, if present.
53
36
        add_arg();
54
55
        // Consume flags.
56
40
        while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it;
57
58
36
        auto parse_size = [&] {
59
36
            if (*it == '*') {
60
36
                ++it;
61
36
                add_arg();
62
36
            } else {
63
36
                while ('0' <= *it && *it <= '9') ++it;
64
36
            }
65
36
        };
66
67
        // Consume dynamic or static width value.
68
36
        parse_size();
69
70
        // Consume dynamic or static precision value.
71
36
        if (*it == '.') {
72
9
            ++it;
73
9
            parse_size();
74
9
        }
75
76
36
        if (*it == '\0') throw "Format specifier incorrectly terminated by end of string";
77
78
        // Length and type in "[flags][width][.precision][length]type"
79
        // is not checked. Parsing continues with the next '%'.
80
36
    }
81
25
    if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
82
24
    unsigned count{count_normal | count_pos};
83
24
    if (num_params != count) throw "Format specifier count must match the argument count!";
84
24
}
void util::detail::CheckNumFormatSpecifiers<3u>(char const*)
Line
Count
Source
27
10
{
28
10
    unsigned count_normal{0}; // Number of "normal" specifiers, like %s
29
10
    unsigned count_pos{0};    // Max number in positional specifier, like %8$s
30
24
    for (auto it{str}; *it != '\0'; ++it) {
31
14
        if (*it != '%' || *++it == '%') continue; // Skip escaped %%
32
33
10
        auto add_arg = [&] {
34
10
            unsigned maybe_num{0};
35
10
            while ('0' <= *it && *it <= '9') {
36
10
                maybe_num *= 10;
37
10
                maybe_num += *it - '0';
38
10
                ++it;
39
10
            }
40
41
10
            if (*it == '$') {
42
10
                ++it;
43
                // Positional specifier, like %8$s
44
10
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
10
                count_pos = std::max(count_pos, maybe_num);
46
10
            } else {
47
                // Non-positional specifier, like %s
48
10
                ++count_normal;
49
10
            }
50
10
        };
51
52
        // Increase argument count and consume positional specifier, if present.
53
10
        add_arg();
54
55
        // Consume flags.
56
19
        while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it;
57
58
10
        auto parse_size = [&] {
59
10
            if (*it == '*') {
60
10
                ++it;
61
10
                add_arg();
62
10
            } else {
63
10
                while ('0' <= *it && *it <= '9') ++it;
64
10
            }
65
10
        };
66
67
        // Consume dynamic or static width value.
68
10
        parse_size();
69
70
        // Consume dynamic or static precision value.
71
10
        if (*it == '.') {
72
9
            ++it;
73
9
            parse_size();
74
9
        }
75
76
10
        if (*it == '\0') throw "Format specifier incorrectly terminated by end of string";
77
78
        // Length and type in "[flags][width][.precision][length]type"
79
        // is not checked. Parsing continues with the next '%'.
80
10
    }
81
10
    if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
82
10
    unsigned count{count_normal | count_pos};
83
10
    if (num_params != count) throw "Format specifier count must match the argument count!";
84
10
}
Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<5u>(char const*)
void util::detail::CheckNumFormatSpecifiers<0u>(char const*)
Line
Count
Source
27
9
{
28
9
    unsigned count_normal{0}; // Number of "normal" specifiers, like %s
29
9
    unsigned count_pos{0};    // Max number in positional specifier, like %8$s
30
22
    for (auto it{str}; *it != '\0'; ++it) {
31
13
        if (*it != '%' || *++it == '%') continue; // Skip escaped %%
32
33
4
        auto add_arg = [&] {
34
4
            unsigned maybe_num{0};
35
4
            while ('0' <= *it && *it <= '9') {
36
4
                maybe_num *= 10;
37
4
                maybe_num += *it - '0';
38
4
                ++it;
39
4
            }
40
41
4
            if (*it == '$') {
42
4
                ++it;
43
                // Positional specifier, like %8$s
44
4
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
4
                count_pos = std::max(count_pos, maybe_num);
46
4
            } else {
47
                // Non-positional specifier, like %s
48
4
                ++count_normal;
49
4
            }
50
4
        };
51
52
        // Increase argument count and consume positional specifier, if present.
53
4
        add_arg();
54
55
        // Consume flags.
56
4
        while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it;
57
58
4
        auto parse_size = [&] {
59
4
            if (*it == '*') {
60
4
                ++it;
61
4
                add_arg();
62
4
            } else {
63
4
                while ('0' <= *it && *it <= '9') ++it;
64
4
            }
65
4
        };
66
67
        // Consume dynamic or static width value.
68
4
        parse_size();
69
70
        // Consume dynamic or static precision value.
71
4
        if (*it == '.') {
72
0
            ++it;
73
0
            parse_size();
74
0
        }
75
76
4
        if (*it == '\0') throw "Format specifier incorrectly terminated by end of string";
77
78
        // Length and type in "[flags][width][.precision][length]type"
79
        // is not checked. Parsing continues with the next '%'.
80
4
    }
81
9
    if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
82
9
    unsigned count{count_normal | count_pos};
83
9
    if (num_params != count) throw "Format specifier count must match the argument count!";
84
9
}
Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<6u>(char const*)
void util::detail::CheckNumFormatSpecifiers<4u>(char const*)
Line
Count
Source
27
1
{
28
1
    unsigned count_normal{0}; // Number of "normal" specifiers, like %s
29
1
    unsigned count_pos{0};    // Max number in positional specifier, like %8$s
30
2
    for (auto it{str}; *it != '\0'; ++it) {
31
1
        if (*it != '%' || *++it == '%') continue; // Skip escaped %%
32
33
1
        auto add_arg = [&] {
34
1
            unsigned maybe_num{0};
35
1
            while ('0' <= *it && *it <= '9') {
36
1
                maybe_num *= 10;
37
1
                maybe_num += *it - '0';
38
1
                ++it;
39
1
            }
40
41
1
            if (*it == '$') {
42
1
                ++it;
43
                // Positional specifier, like %8$s
44
1
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
1
                count_pos = std::max(count_pos, maybe_num);
46
1
            } else {
47
                // Non-positional specifier, like %s
48
1
                ++count_normal;
49
1
            }
50
1
        };
51
52
        // Increase argument count and consume positional specifier, if present.
53
1
        add_arg();
54
55
        // Consume flags.
56
1
        while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it;
57
58
1
        auto parse_size = [&] {
59
1
            if (*it == '*') {
60
1
                ++it;
61
1
                add_arg();
62
1
            } else {
63
1
                while ('0' <= *it && *it <= '9') ++it;
64
1
            }
65
1
        };
66
67
        // Consume dynamic or static width value.
68
1
        parse_size();
69
70
        // Consume dynamic or static precision value.
71
1
        if (*it == '.') {
72
1
            ++it;
73
1
            parse_size();
74
1
        }
75
76
1
        if (*it == '\0') throw "Format specifier incorrectly terminated by end of string";
77
78
        // Length and type in "[flags][width][.precision][length]type"
79
        // is not checked. Parsing continues with the next '%'.
80
1
    }
81
1
    if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
82
1
    unsigned count{count_normal | count_pos};
83
1
    if (num_params != count) throw "Format specifier count must match the argument count!";
84
1
}
void util::detail::CheckNumFormatSpecifiers<129u>(char const*)
Line
Count
Source
27
1
{
28
1
    unsigned count_normal{0}; // Number of "normal" specifiers, like %s
29
1
    unsigned count_pos{0};    // Max number in positional specifier, like %8$s
30
10
    for (auto it{str}; *it != '\0'; ++it) {
31
9
        if (*it != '%' || *++it == '%') continue; // Skip escaped %%
32
33
2
        auto add_arg = [&] {
34
2
            unsigned maybe_num{0};
35
2
            while ('0' <= *it && *it <= '9') {
36
2
                maybe_num *= 10;
37
2
                maybe_num += *it - '0';
38
2
                ++it;
39
2
            }
40
41
2
            if (*it == '$') {
42
2
                ++it;
43
                // Positional specifier, like %8$s
44
2
                if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
45
2
                count_pos = std::max(count_pos, maybe_num);
46
2
            } else {
47
                // Non-positional specifier, like %s
48
2
                ++count_normal;
49
2
            }
50
2
        };
51
52
        // Increase argument count and consume positional specifier, if present.
53
2
        add_arg();
54
55
        // Consume flags.
56
2
        while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it;
57
58
2
        auto parse_size = [&] {
59
2
            if (*it == '*') {
60
2
                ++it;
61
2
                add_arg();
62
2
            } else {
63
2
                while ('0' <= *it && *it <= '9') ++it;
64
2
            }
65
2
        };
66
67
        // Consume dynamic or static width value.
68
2
        parse_size();
69
70
        // Consume dynamic or static precision value.
71
2
        if (*it == '.') {
72
0
            ++it;
73
0
            parse_size();
74
0
        }
75
76
2
        if (*it == '\0') throw "Format specifier incorrectly terminated by end of string";
77
78
        // Length and type in "[flags][width][.precision][length]type"
79
        // is not checked. Parsing continues with the next '%'.
80
2
    }
81
1
    if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
82
1
    unsigned count{count_normal | count_pos};
83
1
    if (num_params != count) throw "Format specifier count must match the argument count!";
84
1
}
Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<7u>(char const*)
Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<18u>(char const*)
Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<19u>(char const*)
Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<12u>(char const*)
Unexecuted instantiation: void util::detail::CheckNumFormatSpecifiers<8u>(char const*)
85
} // namespace detail
86
87
/**
88
 * @brief A wrapper for a compile-time partially validated format string
89
 *
90
 * This struct can be used to enforce partial compile-time validation of format
91
 * strings, to reduce the likelihood of tinyformat throwing exceptions at
92
 * run-time. Validation is partial to try and prevent the most common errors
93
 * while avoiding re-implementing the entire parsing logic.
94
 */
95
template <unsigned num_params>
96
struct ConstevalFormatString {
97
    const char* const fmt;
98
    consteval ConstevalFormatString(const char* str) : fmt{str} { detail::CheckNumFormatSpecifiers<num_params>(fmt); }
99
};
100
101
/// Replace every non-overlapping occurrence of `search` with `substitute`, treating both literally; the replacement text is not searched again.
102
void ReplaceAll(std::string& in_out, std::string_view search, std::string_view substitute);
103
104
/** Split a string on any char found in separators, returning a vector.
105
 *
106
 * If sep does not occur in sp, a singleton with the entirety of sp is returned.
107
 *
108
 * @param[in] include_sep Whether to include the separator at the end of the left side of the splits.
109
 *
110
 * Note that this function does not care about braces, so splitting
111
 * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}.
112
 *
113
 * If include_sep == true, splitting "foo(bar(1),2),3) on ','
114
 * will return:
115
 *  - foo(bar(1),
116
 *  - 2),
117
 *  - 3)
118
 */
119
template <typename T = std::span<const char>>
120
std::vector<T> Split(std::span<const char> sp LIFETIMEBOUND, std::string_view separators, bool include_sep = false)
121
1.74M
{
122
1.74M
    std::vector<T> ret;
123
1.74M
    auto it = sp.begin();
124
1.74M
    auto start = it;
125
26.0M
    while (it != sp.end()) {
126
24.2M
        if (separators.find(*it) != std::string::npos) {
127
651k
            if (include_sep) {
128
189
                ret.emplace_back(start, it + 1);
129
650k
            } else {
130
650k
                ret.emplace_back(start, it);
131
650k
            }
132
651k
            start = it + 1;
133
651k
        }
134
24.2M
        ++it;
135
24.2M
    }
136
1.74M
    ret.emplace_back(start, it);
137
1.74M
    return ret;
138
1.74M
}
std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> util::Split<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>(std::span<char const, 18446744073709551615ul>, std::basic_string_view<char, std::char_traits<char>>, bool)
Line
Count
Source
121
1.29M
{
122
1.29M
    std::vector<T> ret;
123
1.29M
    auto it = sp.begin();
124
1.29M
    auto start = it;
125
12.9M
    while (it != sp.end()) {
126
11.6M
        if (separators.find(*it) != std::string::npos) {
127
39.4k
            if (include_sep) {
128
0
                ret.emplace_back(start, it + 1);
129
39.4k
            } else {
130
39.4k
                ret.emplace_back(start, it);
131
39.4k
            }
132
39.4k
            start = it + 1;
133
39.4k
        }
134
11.6M
        ++it;
135
11.6M
    }
136
1.29M
    ret.emplace_back(start, it);
137
1.29M
    return ret;
138
1.29M
}
std::vector<std::span<char const, 18446744073709551615ul>, std::allocator<std::span<char const, 18446744073709551615ul>>> util::Split<std::span<char const, 18446744073709551615ul>>(std::span<char const, 18446744073709551615ul>, std::basic_string_view<char, std::char_traits<char>>, bool)
Line
Count
Source
121
77.0k
{
122
77.0k
    std::vector<T> ret;
123
77.0k
    auto it = sp.begin();
124
77.0k
    auto start = it;
125
8.95M
    while (it != sp.end()) {
126
8.87M
        if (separators.find(*it) != std::string::npos) {
127
52.7k
            if (include_sep) {
128
189
                ret.emplace_back(start, it + 1);
129
52.5k
            } else {
130
52.5k
                ret.emplace_back(start, it);
131
52.5k
            }
132
52.7k
            start = it + 1;
133
52.7k
        }
134
8.87M
        ++it;
135
8.87M
    }
136
77.0k
    ret.emplace_back(start, it);
137
77.0k
    return ret;
138
77.0k
}
std::vector<std::basic_string_view<char, std::char_traits<char>>, std::allocator<std::basic_string_view<char, std::char_traits<char>>>> util::Split<std::basic_string_view<char, std::char_traits<char>>>(std::span<char const, 18446744073709551615ul>, std::basic_string_view<char, std::char_traits<char>>, bool)
Line
Count
Source
121
372k
{
122
372k
    std::vector<T> ret;
123
372k
    auto it = sp.begin();
124
372k
    auto start = it;
125
4.14M
    while (it != sp.end()) {
126
3.77M
        if (separators.find(*it) != std::string::npos) {
127
558k
            if (include_sep) {
128
0
                ret.emplace_back(start, it + 1);
129
558k
            } else {
130
558k
                ret.emplace_back(start, it);
131
558k
            }
132
558k
            start = it + 1;
133
558k
        }
134
3.77M
        ++it;
135
3.77M
    }
136
372k
    ret.emplace_back(start, it);
137
372k
    return ret;
138
372k
}
139
140
/** Split a string on every instance of sep, returning a vector.
141
 *
142
 * If sep does not occur in sp, a singleton with the entirety of sp is returned.
143
 *
144
 * Note that this function does not care about braces, so splitting
145
 * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}.
146
 */
147
template <typename T = std::span<const char>>
148
std::vector<T> Split(std::span<const char> sp LIFETIMEBOUND, char sep, bool include_sep = false)
149
1.36M
{
150
1.36M
    return Split<T>(sp, std::string_view{&sep, 1}, include_sep);
151
1.36M
}
std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> util::Split<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>(std::span<char const, 18446744073709551615ul>, char, bool)
Line
Count
Source
149
1.28M
{
150
1.28M
    return Split<T>(sp, std::string_view{&sep, 1}, include_sep);
151
1.28M
}
std::vector<std::span<char const, 18446744073709551615ul>, std::allocator<std::span<char const, 18446744073709551615ul>>> util::Split<std::span<char const, 18446744073709551615ul>>(std::span<char const, 18446744073709551615ul>, char, bool)
Line
Count
Source
149
76.6k
{
150
76.6k
    return Split<T>(sp, std::string_view{&sep, 1}, include_sep);
151
76.6k
}
std::vector<std::basic_string_view<char, std::char_traits<char>>, std::allocator<std::basic_string_view<char, std::char_traits<char>>>> util::Split<std::basic_string_view<char, std::char_traits<char>>>(std::span<char const, 18446744073709551615ul>, char, bool)
Line
Count
Source
149
53
{
150
53
    return Split<T>(sp, std::string_view{&sep, 1}, include_sep);
151
53
}
152
153
[[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep)
154
1.28M
{
155
1.28M
    return Split<std::string>(str, sep);
156
1.28M
}
157
158
[[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, std::string_view separators)
159
2.83k
{
160
2.83k
    return Split<std::string>(str, separators);
161
2.83k
}
162
163
[[nodiscard]] inline std::string_view TrimStringView(std::string_view str LIFETIMEBOUND, std::string_view pattern = " \f\n\r\t\v")
164
2.39M
{
165
2.39M
    std::string::size_type front = str.find_first_not_of(pattern);
166
2.39M
    if (front == std::string::npos) {
167
103
        return {};
168
103
    }
169
2.39M
    std::string::size_type end = str.find_last_not_of(pattern);
170
2.39M
    return str.substr(front, end - front + 1);
171
2.39M
}
172
173
[[nodiscard]] inline std::string TrimString(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
174
1.60M
{
175
1.60M
    return std::string(TrimStringView(str, pattern));
176
1.60M
}
177
178
[[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str LIFETIMEBOUND, std::string_view suffix)
179
1.61k
{
180
1.61k
    if (str.ends_with(suffix)) {
181
1.61k
        return str.substr(0, str.size() - suffix.size());
182
1.61k
    }
183
0
    return str;
184
1.61k
}
185
186
[[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str LIFETIMEBOUND, std::string_view prefix)
187
5.74M
{
188
5.74M
    if (str.starts_with(prefix)) {
189
72
        return str.substr(prefix.size());
190
72
    }
191
5.74M
    return str;
192
5.74M
}
193
194
[[nodiscard]] inline std::string RemovePrefix(std::string_view str, std::string_view prefix)
195
11
{
196
11
    return std::string(RemovePrefixView(str, prefix));
197
11
}
198
199
/**
200
 * Join all container items. Typically used to concatenate strings but accepts
201
 * containers with elements of any type.
202
 *
203
 * @param container The items to join
204
 * @param separator The separator
205
 * @param unary_op  Apply this operator to each item
206
 */
207
template <typename C, typename S, typename UnaryOp>
208
// NOLINTNEXTLINE(misc-no-recursion)
209
auto Join(const C& container, const S& separator, UnaryOp unary_op)
210
283k
{
211
283k
    decltype(unary_op(*container.begin())) ret;
212
283k
    bool first{true};
213
1.30M
    for (const auto& item : container) {
214
1.30M
        if (!first) ret += separator;
215
1.30M
        ret += unary_op(item);
216
1.30M
        first = false;
217
1.30M
    }
218
283k
    return ret;
219
283k
}
auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2], util::MakeUnorderedList(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)::'lambda'(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&)>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2], util::MakeUnorderedList(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)::'lambda'(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&))
Line
Count
Source
210
2.47k
{
211
2.47k
    decltype(unary_op(*container.begin())) ret;
212
2.47k
    bool first{true};
213
14.8k
    for (const auto& item : container) {
214
14.8k
        if (!first) ret += separator;
215
14.8k
        ret += unary_op(item);
216
14.8k
        first = false;
217
14.8k
    }
218
2.47k
    return ret;
219
2.47k
}
auto util::Join<std::vector<LogCategory, std::allocator<LogCategory>>, char [3], BCLog::Logger::LogCategoriesString[abi:cxx11]() const::'lambda'(LogCategory const&)>(std::vector<LogCategory, std::allocator<LogCategory>> const&, char const (&) [3], BCLog::Logger::LogCategoriesString[abi:cxx11]() const::'lambda'(LogCategory const&))
Line
Count
Source
210
6.48k
{
211
6.48k
    decltype(unary_op(*container.begin())) ret;
212
6.48k
    bool first{true};
213
194k
    for (const auto& item : container) {
214
194k
        if (!first) ret += separator;
215
194k
        ret += unary_op(item);
216
194k
        first = false;
217
194k
    }
218
6.48k
    return ret;
219
6.48k
}
auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2], auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2], auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&))
Line
Count
Source
210
184
{
211
184
    decltype(unary_op(*container.begin())) ret;
212
184
    bool first{true};
213
226
    for (const auto& item : container) {
214
226
        if (!first) ret += separator;
215
226
        ret += unary_op(item);
216
226
        first = false;
217
226
    }
218
184
    return ret;
219
184
}
auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3], auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3], auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&))
Line
Count
Source
210
119k
{
211
119k
    decltype(unary_op(*container.begin())) ret;
212
119k
    bool first{true};
213
958k
    for (const auto& item : container) {
214
958k
        if (!first) ret += separator;
215
958k
        ret += unary_op(item);
216
958k
        first = false;
217
958k
    }
218
119k
    return ret;
219
119k
}
util_tests.cpp:auto util::Join<std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3], util_tests::util_Join::test_method()::$_0>(std::__cxx11::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3], util_tests::util_Join::test_method()::$_0)
Line
Count
Source
210
6
{
211
6
    decltype(unary_op(*container.begin())) ret;
212
6
    bool first{true};
213
6
    for (const auto& item : container) {
214
6
        if (!first) ret += separator;
215
6
        ret += unary_op(item);
216
6
        first = false;
217
6
    }
218
6
    return ret;
219
6
}
coinselection_tests.cpp:auto util::Join<std::set<std::shared_ptr<wallet::COutput>, wallet::OutputPtrComparator, std::allocator<std::shared_ptr<wallet::COutput>>>, char [2], wallet::coinselection_tests::InputAmountsToString[abi:cxx11](wallet::SelectionResult const&)::$_0>(std::set<std::shared_ptr<wallet::COutput>, wallet::OutputPtrComparator, std::allocator<std::shared_ptr<wallet::COutput>>> const&, char const (&) [2], wallet::coinselection_tests::InputAmountsToString[abi:cxx11](wallet::SelectionResult const&)::$_0)
Line
Count
Source
210
208
{
211
208
    decltype(unary_op(*container.begin())) ret;
212
208
    bool first{true};
213
636
    for (const auto& item : container) {
214
636
        if (!first) ret += separator;
215
636
        ret += unary_op(item);
216
636
        first = false;
217
636
    }
218
208
    return ret;
219
208
}
blockfilter.cpp:auto util::Join<std::map<BlockFilterType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::less<BlockFilterType>, std::allocator<std::pair<BlockFilterType const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>>, char [3], ListBlockFilterTypes()::$_0>(std::map<BlockFilterType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::less<BlockFilterType>, std::allocator<std::pair<BlockFilterType const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>> const&, char const (&) [3], ListBlockFilterTypes()::$_0)
Line
Count
Source
210
1.37k
{
211
1.37k
    decltype(unary_op(*container.begin())) ret;
212
1.37k
    bool first{true};
213
1.37k
    for (const auto& item : container) {
214
1.37k
        if (!first) ret += separator;
215
1.37k
        ret += unary_op(item);
216
1.37k
        first = false;
217
1.37k
    }
218
1.37k
    return ret;
219
1.37k
}
auto util::Join<std::vector<bilingual_str, std::allocator<bilingual_str>>, bilingual_str, auto util::Join<std::vector<bilingual_str, std::allocator<bilingual_str>>, bilingual_str>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&, bilingual_str const&)::'lambda'(std::vector<bilingual_str, std::allocator<bilingual_str>> const&)>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&, bilingual_str const&, auto util::Join<std::vector<bilingual_str, std::allocator<bilingual_str>>, bilingual_str>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&, bilingual_str const&)::'lambda'(std::vector<bilingual_str, std::allocator<bilingual_str>> const&))
Line
Count
Source
210
114k
{
211
114k
    decltype(unary_op(*container.begin())) ret;
212
114k
    bool first{true};
213
114k
    for (const auto& item : container) {
214
146
        if (!first) ret += separator;
215
146
        ret += unary_op(item);
216
146
        first = false;
217
146
    }
218
114k
    return ret;
219
114k
}
validation.cpp:auto util::Join<std::vector<int, std::allocator<int>>, char [3], ChainstateManager::ActivateSnapshot(AutoFile&, node::SnapshotMetadata const&, bool)::$_0>(std::vector<int, std::allocator<int>> const&, char const (&) [3], ChainstateManager::ActivateSnapshot(AutoFile&, node::SnapshotMetadata const&, bool)::$_0)
Line
Count
Source
210
14
{
211
14
    decltype(unary_op(*container.begin())) ret;
212
14
    bool first{true};
213
42
    for (const auto& item : container) {
214
42
        if (!first) ret += separator;
215
42
        ret += unary_op(item);
216
42
        first = false;
217
42
    }
218
14
    return ret;
219
14
}
messages.cpp:auto util::Join<std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, FeeEstimateMode>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, FeeEstimateMode>>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, common::FeeModes(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&)::$_0>(std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, FeeEstimateMode>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, FeeEstimateMode>>> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, common::FeeModes(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&)::$_0)
Line
Count
Source
210
13.9k
{
211
13.9k
    decltype(unary_op(*container.begin())) ret;
212
13.9k
    bool first{true};
213
41.9k
    for (const auto& item : container) {
214
41.9k
        if (!first) ret += separator;
215
41.9k
        ret += unary_op(item);
216
41.9k
        first = false;
217
41.9k
    }
218
13.9k
    return ret;
219
13.9k
}
outputtype.cpp:auto util::Join<std::array<OutputType, 4ul>, char [3], FormatAllOutputTypes[abi:cxx11]()::$_0>(std::array<OutputType, 4ul> const&, char const (&) [3], FormatAllOutputTypes[abi:cxx11]()::$_0)
Line
Count
Source
210
22.1k
{
211
22.1k
    decltype(unary_op(*container.begin())) ret;
212
22.1k
    bool first{true};
213
88.7k
    for (const auto& item : container) {
214
88.7k
        if (!first) ret += separator;
215
88.7k
        ret += unary_op(item);
216
88.7k
        first = false;
217
88.7k
    }
218
22.1k
    return ret;
219
22.1k
}
util.cpp:auto util::Join<std::vector<RPCArg, std::allocator<RPCArg>>, char [2], RPCArg::ToString[abi:cxx11](bool) const::$_0>(std::vector<RPCArg, std::allocator<RPCArg>> const&, char const (&) [2], RPCArg::ToString[abi:cxx11](bool) const::$_0)
Line
Count
Source
210
180
{
211
180
    decltype(unary_op(*container.begin())) ret;
212
180
    bool first{true};
213
398
    for (const auto& item : container) {
214
398
        if (!first) ret += separator;
215
398
        ret += unary_op(item);
216
398
        first = false;
217
398
    }
218
180
    return ret;
219
180
}
logging.cpp:auto util::Join<std::vector<util::log::Level, std::allocator<util::log::Level>>, char [3], BCLog::Logger::LogLevelsString[abi:cxx11]() const::$_0>(std::vector<util::log::Level, std::allocator<util::log::Level>> const&, char const (&) [3], BCLog::Logger::LogLevelsString[abi:cxx11]() const::$_0)
Line
Count
Source
210
2.00k
{
211
2.00k
    decltype(unary_op(*container.begin())) ret;
212
2.00k
    bool first{true};
213
6.00k
    for (const auto& item : container) {
214
6.00k
        if (!first) ret += separator;
215
6.00k
        ret += unary_op(item);
216
6.00k
        first = false;
217
6.00k
    }
218
2.00k
    return ret;
219
2.00k
}
220
221
template <typename C, typename S>
222
auto Join(const C& container, const S& separator)
223
234k
{
224
959k
    return Join(container, separator, [](const auto& i) { return i; });
auto auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)::operator()<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&) const
Line
Count
Source
224
226
    return Join(container, separator, [](const auto& i) { return i; });
auto auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3])::'lambda'(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&)::operator()<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&) const
Line
Count
Source
224
958k
    return Join(container, separator, [](const auto& i) { return i; });
auto auto util::Join<std::vector<bilingual_str, std::allocator<bilingual_str>>, bilingual_str>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&, bilingual_str const&)::'lambda'(std::vector<bilingual_str, std::allocator<bilingual_str>> const&)::operator()<bilingual_str>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&) const
Line
Count
Source
224
146
    return Join(container, separator, [](const auto& i) { return i; });
225
234k
}
auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [2]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [2])
Line
Count
Source
223
184
{
224
184
    return Join(container, separator, [](const auto& i) { return i; });
225
184
}
auto util::Join<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, char [3]>(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, char const (&) [3])
Line
Count
Source
223
119k
{
224
119k
    return Join(container, separator, [](const auto& i) { return i; });
225
119k
}
auto util::Join<std::vector<bilingual_str, std::allocator<bilingual_str>>, bilingual_str>(std::vector<bilingual_str, std::allocator<bilingual_str>> const&, bilingual_str const&)
Line
Count
Source
223
114k
{
224
114k
    return Join(container, separator, [](const auto& i) { return i; });
225
114k
}
226
227
/**
228
 * Create an unordered multi-line list of items.
229
 */
230
inline std::string MakeUnorderedList(const std::vector<std::string>& items)
231
2.47k
{
232
14.8k
    return Join(items, "\n", [](const std::string& item) { return "- " + item; });
233
2.47k
}
234
235
/**
236
 * Check if a string contains any embedded NUL (\0) characters
237
 */
238
[[nodiscard]] inline bool ContainsNUL(std::string_view str) noexcept
239
200k
{
240
4.08M
    for (auto c : str) {
241
4.08M
        if (c == 0) return true;
242
4.08M
    }
243
200k
    return false;
244
200k
}
245
246
/**
247
 * Locale-independent version of std::to_string
248
 */
249
template <typename T>
250
std::string ToString(const T& t)
251
444k
{
252
444k
    std::ostringstream oss;
253
444k
    oss.imbue(std::locale::classic());
254
444k
    oss << t;
255
444k
    return oss.str();
256
444k
}
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<unsigned int>(unsigned int const&)
Line
Count
Source
251
8.20k
{
252
8.20k
    std::ostringstream oss;
253
8.20k
    oss.imbue(std::locale::classic());
254
8.20k
    oss << t;
255
8.20k
    return oss.str();
256
8.20k
}
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<int>(int const&)
Line
Count
Source
251
223k
{
252
223k
    std::ostringstream oss;
253
223k
    oss.imbue(std::locale::classic());
254
223k
    oss << t;
255
223k
    return oss.str();
256
223k
}
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<double>(double const&)
Line
Count
Source
251
10
{
252
10
    std::ostringstream oss;
253
10
    oss.imbue(std::locale::classic());
254
10
    oss << t;
255
10
    return oss.str();
256
10
}
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<unsigned long>(unsigned long const&)
Line
Count
Source
251
188k
{
252
188k
    std::ostringstream oss;
253
188k
    oss.imbue(std::locale::classic());
254
188k
    oss << t;
255
188k
    return oss.str();
256
188k
}
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<unsigned short>(unsigned short const&)
Line
Count
Source
251
1
{
252
1
    std::ostringstream oss;
253
1
    oss.imbue(std::locale::classic());
254
1
    oss << t;
255
1
    return oss.str();
256
1
}
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> util::ToString<long>(long const&)
Line
Count
Source
251
24.9k
{
252
24.9k
    std::ostringstream oss;
253
24.9k
    oss.imbue(std::locale::classic());
254
24.9k
    oss << t;
255
24.9k
    return oss.str();
256
24.9k
}
257
258
/**
259
 * Check whether a container begins with the given prefix.
260
 */
261
template <typename T1, size_t PREFIX_LEN>
262
[[nodiscard]] inline bool HasPrefix(const T1& obj,
263
                                const std::array<uint8_t, PREFIX_LEN>& prefix)
264
4.03M
{
265
4.03M
    return obj.size() >= PREFIX_LEN &&
266
4.03M
           std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
267
4.03M
}
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 6ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 6ul> const&)
Line
Count
Source
264
118
{
265
118
    return obj.size() >= PREFIX_LEN &&
266
118
           std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
267
118
}
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 12ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 12ul> const&)
Line
Count
Source
264
1.74k
{
265
1.74k
    return obj.size() >= PREFIX_LEN &&
266
1.74k
           std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
267
1.74k
}
bool util::HasPrefix<std::span<unsigned char const, 18446744073709551615ul>, 12ul>(std::span<unsigned char const, 18446744073709551615ul> const&, std::array<unsigned char, 12ul> const&)
Line
Count
Source
264
10.1k
{
265
10.1k
    return obj.size() >= PREFIX_LEN &&
266
10.1k
           std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
267
10.1k
}
bool util::HasPrefix<std::span<unsigned char const, 18446744073709551615ul>, 6ul>(std::span<unsigned char const, 18446744073709551615ul> const&, std::array<unsigned char, 6ul> const&)
Line
Count
Source
264
6.82k
{
265
6.82k
    return obj.size() >= PREFIX_LEN &&
266
6.82k
           std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
267
6.82k
}
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 2ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 2ul> const&)
Line
Count
Source
264
1.00M
{
265
1.00M
    return obj.size() >= PREFIX_LEN &&
266
1.00M
           std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
267
1.00M
}
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 3ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 3ul> const&)
Line
Count
Source
264
3.00M
{
265
3.00M
    return obj.size() >= PREFIX_LEN &&
266
3.00M
           std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
267
3.00M
}
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 4ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 4ul> const&)
Line
Count
Source
264
3.40k
{
265
3.40k
    return obj.size() >= PREFIX_LEN &&
266
3.40k
           std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
267
3.40k
}
bool util::HasPrefix<prevector<16u, unsigned char, unsigned int, int>, 8ul>(prevector<16u, unsigned char, unsigned int, int> const&, std::array<unsigned char, 8ul> const&)
Line
Count
Source
264
2.24k
{
265
2.24k
    return obj.size() >= PREFIX_LEN &&
266
2.24k
           std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
267
2.24k
}
268
269
class LineReader
270
{
271
    const std::string_view m_str;
272
    const size_t m_max_line_length;
273
    std::string_view::iterator m_it;
274
275
public:
276
    explicit LineReader(std::string_view str LIFETIMEBOUND, size_t max_line_length);
277
278
    /**
279
     * Returns a string from current iterator position up to (but not including) next \n
280
     * and advances iterator to the character following the \n on success.
281
     * Will not return a line longer than max_line_length.
282
     * @returns the next string from the buffer.
283
     *          std::nullopt if end of buffer is reached without finding a \n.
284
     * @throws a std::runtime_error if max_line_length + 1 bytes are read without finding \n.
285
     */
286
    std::optional<std::string_view> ReadLine() LIFETIMEBOUND;
287
288
    /**
289
     * Returns string from current iterator position of specified length
290
     * if possible and advances iterator on success.
291
     * May exceed max_line_length but will not read past end of buffer.
292
     * @param[in]   len     The number of bytes to read from the buffer
293
     * @returns a string of the expected length.
294
     * @throws a std::runtime_error if there is not enough data in the buffer.
295
     */
296
    std::string_view ReadLength(size_t len) LIFETIMEBOUND;
297
298
    /**
299
     * Returns remaining size of bytes in buffer
300
     */
301
    size_t Remaining() const;
302
303
    /**
304
     * Returns number of bytes already read from buffer
305
     */
306
    size_t Consumed() const;
307
};
308
} // namespace util
309
310
#endif // BITCOIN_UTIL_STRING_H