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

libbitcoin / libbitcoin-system / 18823651969

26 Oct 2025 09:01PM UTC coverage: 80.946% (+0.04%) from 80.903%
18823651969

push

github

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

Simplify and optimize JSON annotation defines.

104 of 136 new or added lines in 16 files covered. (76.47%)

1 existing line in 1 file now uncovered.

10591 of 13084 relevant lines covered (80.95%)

3619070.67 hits per line

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

93.86
/src/data/string.cpp
1
/**
2
 * Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
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 <algorithm>
22
#include <iterator>
23
#include <sstream>
24
#include <utility>
25
#include <bitcoin/system/data/data_slice.hpp>
26
#include <bitcoin/system/define.hpp>
27
#include <bitcoin/system/unicode/unicode.hpp>
28

29
namespace libbitcoin {
30
namespace system {
31

32
std::string join(const string_list& tokens,
44,213✔
33
    const std::string& delimiter) NOEXCEPT
34
{
35
    if (tokens.empty())
44,213✔
36
        return {};
8✔
37

38
    // Start with the first token.
39
    std::ostringstream sentence;
44,205✔
40

41
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
42
    sentence << tokens.front();
44,205✔
43

44
    // Add remaining tokens preceded by delimiters.
45
    for (auto token = std::next(tokens.begin()); token != tokens.end(); ++token)
422,817✔
46
        sentence << delimiter << *token;
378,612✔
47

48
    return sentence.str();
44,205✔
49
    BC_POP_WARNING()
50
}
44,205✔
51

52
void reduce(string_list& tokens, const string_list& trim_tokens,
34,597✔
53
    bool compress) NOEXCEPT
54
{
55
    static const std::string empty{};
34,597✔
56

57
    if (tokens.empty())
34,597✔
58
        return;
59

60
    for (auto& token: tokens)
263,254✔
61
        trim(token, trim_tokens);
228,658✔
62

63
    if (compress)
34,596✔
64
        std::erase(tokens, empty);
34,429✔
65

66
    if (tokens.empty())
34,596✔
67
        tokens.push_back({});
164✔
68
}
69

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

78
size_t replace(std::string& text, const std::string& from,
175,031✔
79
    const std::string& to) NOEXCEPT
80
{
81
    auto count = zero;
175,031✔
82
    if (from.empty())
175,031✔
83
        return count;
84

85
    for (auto position = text.find(from);
363,968✔
86
        position != std::string::npos;
363,968✔
87
        position = text.find(from, position + to.length()))
188,938✔
88
    {
89
        ++count;
188,938✔
90
        text.replace(position, from.length(), to);
188,938✔
91
    }
92

93
    return count;
94
}
95

96
std::string replace_copy(const std::string& text, const std::string& from,
2✔
97
    const std::string& to) NOEXCEPT
98
{
99
    std::string copy{ text };
2✔
100
    replace(copy, from, to);
2✔
101
    return copy;
2✔
102
}
103

104
static string_list splitter(const std::string& text, const std::string& delimiter,
34,589✔
105
    const string_list& trim_tokens, bool compress) NOEXCEPT
106
{
107
    auto start = zero;
34,589✔
108
    string_list tokens;
34,589✔
109

110
    // Push all but the last token.
111
    for (auto position = text.find(delimiter);
34,589✔
112
        position != std::string::npos;
228,637✔
113
        position = text.find(delimiter, start))
194,048✔
114
    {
115
        tokens.push_back(text.substr(start, position - start));
194,048✔
116
        start = position + delimiter.length();
194,048✔
117
    }
118

119
    // Push last token (delimiter not found).
120
    tokens.push_back(text.substr(start, text.length() - start));
34,589✔
121
    reduce(tokens, trim_tokens, compress);
34,589✔
122
    return tokens;
34,589✔
123
}
124

125
string_list split(const std::string_view& text, const string_list& delimiters,
34,589✔
126
    const string_list& trim_tokens, bool compress) NOEXCEPT
127
{
128
    // Nothing to do.
129
    if (delimiters.empty() && trim_tokens.empty())
34,589✔
NEW
130
        return { std::string{ text } };
×
131

132
    // Trim first to preclude outer empty otherwise trimmable outer tokens.
133
    auto trimmed = trim_copy(std::string{ text }, trim_tokens);
34,589✔
134

135
    // Nothing more to do.
136
    if (delimiters.empty())
34,589✔
137
        return { trimmed };
×
138

139
    // Replace all other delimiters with the first delimiter.
140
    for (auto it = std::next(delimiters.begin()); it != delimiters.end(); ++it)
209,607✔
141
        replace(trimmed, *it, delimiters.front());
175,018✔
142

143
    // Split on the first delimiter and conditionally compress empty tokens.
144
    return splitter(trimmed, delimiters.front(), trim_tokens, compress);
34,589✔
UNCOV
145
}
×
146

147
string_list split(const std::string_view& text, const std::string& delimiter,
251✔
148
    bool trim, bool compress) NOEXCEPT
149
{
150
    const auto trim_tokens = trim ? ascii_whitespace : string_list{};
251✔
151
    return split(text, string_list{ delimiter }, trim_tokens, compress);
502✔
152
}
251✔
153

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

161
bool trim_left(std::string& text, const std::string& token) NOEXCEPT
1,762,573✔
162
{
163
    auto found = false;
1,762,573✔
164
    const auto length = token.length();
1,762,573✔
165
    while (starts_with(text, token))
1,762,788✔
166
    {
167
        found = true;
215✔
168
        text.erase(zero, length);
215✔
169
    }
170
    text.shrink_to_fit();
1,762,573✔
171
    return found;
1,762,573✔
172
}
173

174
bool trim_right(std::string& text, const std::string& token) NOEXCEPT
1,762,615✔
175
{
176
    auto found = false;
1,762,615✔
177
    const auto length = token.length();
1,762,615✔
178
    while (ends_with(text, token))
1,763,119✔
179
    {
180
        found = true;
504✔
181
        text.erase(text.length() - length);
504✔
182
    }
183
    text.shrink_to_fit();
1,762,615✔
184
    return found;
1,762,615✔
185
}
186

187
bool trim_left(std::string& text, const string_list& trim_tokens) NOEXCEPT
269,775✔
188
{
189
    bool found{};
269,775✔
190
    do
269,914✔
191
    {
192
        found = false;
269,914✔
193
        for (const auto& token: trim_tokens)
2,032,487✔
194
            if (trim_left(text, token))
1,762,573✔
195
                found = true;
191✔
196
    }
197
    while (found);
198
    return found;
269,775✔
199
}
200

201
bool trim_right(std::string& text, const string_list& trim_tokens) NOEXCEPT
269,831✔
202
{
203
    bool found{};
269,831✔
204
    do
269,980✔
205
    {
206
        found = false;
269,980✔
207
        for (const auto& token: trim_tokens)
2,032,595✔
208
            if (trim_right(text, token))
1,762,615✔
209
                found = true;
186✔
210
    }
211
    while (found);
212
    return found;
269,831✔
213
}
214

215
void trim(std::string& text, const string_list& trim_tokens) NOEXCEPT
269,773✔
216
{
217
    trim_left(text, trim_tokens);
269,773✔
218
    trim_right(text, trim_tokens);
269,773✔
219
}
269,773✔
220

221
std::string trim_left_copy(const std::string_view& text,
2✔
222
    const string_list& trim_tokens) NOEXCEPT
223
{
224
    std::string copy{ text };
2✔
225
    trim_left(copy, trim_tokens);
2✔
226
    return copy;
2✔
227
}
228

229
std::string trim_right_copy(const std::string_view& text,
2✔
230
    const string_list& trim_tokens) NOEXCEPT
231
{
232
    std::string copy{ text };
2✔
233
    trim_right(copy, trim_tokens);
2✔
234
    return copy;
2✔
235
}
236

237
std::string trim_copy(const std::string_view& text,
41,110✔
238
    const string_list& trim_tokens) NOEXCEPT
239
{
240
    std::string copy{ text };
41,110✔
241
    trim(copy, trim_tokens);
41,110✔
242
    return copy;
41,110✔
243
}
244

245
bool ends_with(const std::string& text, const std::string& suffix) NOEXCEPT
1,763,123✔
246
{
247
    const auto at = text.rfind(suffix);
1,763,123✔
248
    return at != std::string::npos && (at + suffix.length()) == text.length();
1,763,123✔
249
}
250

251
bool starts_with(const std::string& text, const std::string& prefix) NOEXCEPT
1,774,153✔
252
{
253
    return is_zero(text.find(prefix));
1,774,153✔
254
}
255

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

© 2026 Coveralls, Inc