• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

libbitcoin / libbitcoin-system / 41739337421

03 Nov 2026 11:27PM UTC coverage: 96.274% (-0.6%) from 96.843%
41739337421

push

github

web-flow
Merge pull request #2151 from evoskuil/master

Stop reading on reader failure, export instantiations only for windows libs.

11 of 11 new or added lines in 5 files covered. (100.0%)

302 existing lines in 67 files now uncovered.

26460 of 27484 relevant lines covered (96.27%)

4041533.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.81
/src/data/string.cpp
1
/**
2
 * Copyright (c) 2011-2026 libbitcoin developers
3
 *
4
 * This file is part of libbitcoin.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
#include <bitcoin/system/data/string.hpp>
20

21
#include <sstream>
22
#include <bitcoin/system/data/data_slice.hpp>
23
#include <bitcoin/system/define.hpp>
24
#include <bitcoin/system/unicode/unicode.hpp>
25

26
namespace libbitcoin {
27
namespace system {
28

29
std::string join(const string_list& tokens,
44,302 ✔
30
    const std::string& delimiter) NOEXCEPT
31
{
32
    if (tokens.empty())
44,302 ✔
33
        return {};
8 ✔
34

35
    // Start with the first token.
36
    std::ostringstream sentence;
44,294 ✔
37

38
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
39
    sentence << tokens.front();
44,294 ✔
40

41
    // Add remaining tokens preceded by delimiters.
42
    for (auto token = std::next(tokens.cbegin()); token != tokens.cend(); ++token)
468,268 ✔
43
        sentence << delimiter << *token;
379,680 ✔
44

45
    return sentence.str();
44,294 ✔
46
    BC_POP_WARNING()
47
}
44,294 ✔
48

49
void reduce(string_list& tokens, const string_list& trim_tokens,
35,061 ✔
50
    bool compress) NOEXCEPT
51
{
52
    static const std::string empty{};
35,061 ✔
53

54
    if (tokens.empty())
35,061 ✔
55
        return;
56

57
    for (auto& token: tokens)
268,518 ✔
58
        trim(token, trim_tokens);
233,458 ✔
59

60
    if (compress)
35,060 ✔
61
        std::erase(tokens, empty);
34,770 ✔
62

63
    if (tokens.empty())
35,060 ✔
64
        tokens.push_back({});
107 ✔
65
}
66

67
string_list reduce_copy(const string_list& tokens,
×
68
    const string_list& trim_tokens, bool compress) NOEXCEPT
69
{
70
    string_list copy{ tokens };
×
71
    reduce(copy, trim_tokens, compress);
×
72
    return copy;
×
73
}
×
74

75
size_t replace(std::string& text, const std::string& from,
178,390 ✔
76
    const std::string& to) NOEXCEPT
77
{
78
    auto count = zero;
79
    if (from.empty())
178,390 ✔
80
        return count;
81

82
    for (auto position = text.find(from);
178,389 ✔
83
        position != std::string::npos;
367,507 ✔
84
        position = text.find(from, position + to.length()))
189,118 ✔
85
    {
86
        ++count;
189,118 ✔
87
        text.replace(position, from.length(), to);
189,118 ✔
88
    }
89

90
    return count;
91
}
92

93
std::string replace_copy(const std::string& text, const std::string& from,
16 ✔
94
    const std::string& to) NOEXCEPT
95
{
96
    std::string copy{ text };
16 ✔
97
    replace(copy, from, to);
16 ✔
98
    return copy;
16 ✔
UNCOV
99
}
×
100

101
static string_list splitter(const std::string& text, const std::string& delimiter,
35,053 ✔
102
    const string_list& trim_tokens, bool compress) NOEXCEPT
103
{
104
    auto start = zero;
105
    string_list tokens;
35,053 ✔
106

107
    // Push all but the last token.
108
    for (auto position = text.find(delimiter);
35,053 ✔
109
        position != std::string::npos;
233,437 ✔
110
        position = text.find(delimiter, start))
198,384 ✔
111
    {
112
        tokens.push_back(text.substr(start, position - start));
198,384 ✔
113
        start = position + delimiter.length();
198,384 ✔
114
    }
115

116
    // Push last token (delimiter not found).
117
    tokens.push_back(text.substr(start, text.length() - start));
35,053 ✔
118
    reduce(tokens, trim_tokens, compress);
35,053 ✔
119
    return tokens;
35,053 ✔
120
}
×
121

122
string_list split(const std::string_view& text, const string_list& delimiters,
35,068 ✔
123
    const string_list& trim_tokens, bool compress) NOEXCEPT
124
{
125
    // Nothing to do.
126
    if (delimiters.empty() && trim_tokens.empty())
35,068 ✔
127
        return { std::string{ text } };
30 ✔
128

129
    // Trim first to preclude outer empty otherwise trimmable outer tokens.
130
    auto trimmed = trim_copy(std::string{ text }, trim_tokens);
35,053 ✔
131

132
    // Nothing more to do.
133
    if (delimiters.empty())
35,053 ✔
134
        return { trimmed };
×
135

136
    // Replace all other delimiters with the first delimiter.
137
    for (auto it = std::next(delimiters.cbegin()); it != delimiters.cend(); ++it)
248,467 ✔
138
        replace(trimmed, *it, delimiters.front());
178,361 ✔
139

140
    // Split on the first delimiter and conditionally compress empty tokens.
141
    return splitter(trimmed, delimiters.front(), trim_tokens, compress);
35,053 ✔
142
}
35,083 ✔
143

144
string_list split(const std::string_view& text, const std::string& delimiter,
427 ✔
145
    bool trim, bool compress) NOEXCEPT
146
{
147
    const auto trim_tokens = trim ? ascii_whitespace : string_list{};
427 ✔
148
    return split(text, string_list{ delimiter }, trim_tokens, compress);
1,281 ✔
149
}
854 ✔
150

151
string_list split(const std::string_view& text) NOEXCEPT
34,074 ✔
152
{
153
    // Splitting is prioritized over trimming, because each token is trimmed.
154
    // So trimming is not an option when splitting on the trim characters.
155
    return split(text, ascii_whitespace, ascii_whitespace, true);
34,074 ✔
156
}
157

158
bool trim_left(std::string& text, const std::string& token) NOEXCEPT
1,985,292 ✔
159
{
160
    auto found = false;
161
    const auto length = token.length();
1,985,292 ✔
162
    while (starts_with(text, token))
1,985,523 ✔
163
    {
164
        found = true;
165
        text.erase(zero, length);
231 ✔
166
    }
167
    text.shrink_to_fit();
1,985,292 ✔
168
    return found;
1,985,292 ✔
169
}
170

171
bool trim_right(std::string& text, const std::string& token) NOEXCEPT
1,985,188 ✔
172
{
173
    auto found = false;
174
    const auto length = token.length();
1,985,188 ✔
175
    while (ends_with(text, token))
1,985,701 ✔
176
    {
177
        found = true;
178
        text.erase(text.length() - length);
513 ✔
179
    }
180
    text.shrink_to_fit();
1,985,188 ✔
181
    return found;
1,985,188 ✔
182
}
183

184
bool trim_left(std::string& text, const string_list& trim_tokens) NOEXCEPT
279,322 ✔
185
{
186
    bool found{};
187
    do
279,473 ✔
188
    {
189
        found = false;
190
        for (const auto& token: trim_tokens)
2,264,765 ✔
191
            if (trim_left(text, token))
1,985,292 ✔
192
                found = true;
193
    }
194
    while (found);
195
    return found;
279,322 ✔
196
}
197

198
bool trim_right(std::string& text, const string_list& trim_tokens) NOEXCEPT
279,368 ✔
199
{
200
    bool found{};
201
    do
279,518 ✔
202
    {
203
        found = false;
204
        for (const auto& token: trim_tokens)
2,264,706 ✔
205
            if (trim_right(text, token))
1,985,188 ✔
206
                found = true;
207
    }
208
    while (found);
209
    return found;
279,368 ✔
210
}
211

212
void trim(std::string& text, const string_list& trim_tokens) NOEXCEPT
279,320 ✔
213
{
214
    trim_left(text, trim_tokens);
279,320 ✔
215
    trim_right(text, trim_tokens);
279,320 ✔
216
}
279,320 ✔
217

218
std::string trim_left_copy(const std::string_view& text,
2 ✔
219
    const string_list& trim_tokens) NOEXCEPT
220
{
221
    std::string copy{ text };
2 ✔
222
    trim_left(copy, trim_tokens);
2 ✔
223
    return copy;
2 ✔
UNCOV
224
}
×
225

226
std::string trim_right_copy(const std::string_view& text,
2 ✔
227
    const string_list& trim_tokens) NOEXCEPT
228
{
229
    std::string copy{ text };
2 ✔
230
    trim_right(copy, trim_tokens);
2 ✔
231
    return copy;
2 ✔
UNCOV
232
}
×
233

234
std::string trim_copy(const std::string_view& text,
45,857 ✔
235
    const string_list& trim_tokens) NOEXCEPT
236
{
237
    std::string copy{ text };
45,857 ✔
238
    trim(copy, trim_tokens);
45,857 ✔
239
    return copy;
45,857 ✔
UNCOV
240
}
×
241

242
bool ends_with(const std::string& text, const std::string& suffix) NOEXCEPT
1,985,705 ✔
243
{
244
    const auto at = text.rfind(suffix);
1,985,705 ✔
245
    return at != std::string::npos && (at + suffix.length()) == text.length();
1,985,705 ✔
246
}
247

248
bool starts_with(const std::string& text, const std::string& prefix) NOEXCEPT
1,996,888 ✔
249
{
250
    return is_zero(text.find(prefix));
1,996,888 ✔
251
}
252

253
} // namespace system
254
} // namespace libbitcoin
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc