Skip to content

Commit 5924dad

Browse files
committed
Merge #13671: Remove the boost/algorithm/string/case_conv.hpp dependency
b193d5a Removes the Boost case_conv.hpp dependency. (251) 7a208d9 Implements custom tolower and toupper functions. (251) e2ba043 Implements ParseNetwork unit test. (251) Pull request description: This pull request removes the `boost/algorithm/string/case_conv.hpp` dependency from the project. `boost/algorithm/string/case_conv.hpp` is included for the `boost::to_lower` and `boost::to_upper` template functions. We can replace the calls to these functions with straightforward alternative implementations that use the C++ Standard Library, because the functions are called with `std::string` objects that use standard 7-bit ASCII characters as argument. The refactored implementation should work without the explicit `static_cast<unsigned char>` cast and `unsigned char` lambda return type. Both have been added defensively and to be explicit. Especially in case of the former, behaviour is undefined (potentially result in a crash) if the `std::toupper` argument is not an `unsigned char`. A potential alternative, maybe even preferred, implementation to address the `boost::to_lower` function call in `ParseNetwork(std::string)` could have been: ```c++ if (net == "ipv4" || net == "IPv4") return NET_IPV4; if (net == "ipv6" || net == "IPv6") return NET_IPV6; ``` This alternative implementation would however change the external behaviour of `ParseNetwork(std::string)`. This pull requests includes a unit test to validate the implementation of `ParseNetwork(std::string)` prior and after the removal of the `case_conv.hpp` dependency. `boost/algorithm/string/case_conv.hpp` has been removed from the `EXPECTED_BOOST_INCLUDES` in `test/lint/lint-includes.sh` because it is no longer required. Tree-SHA512: d803ae709f2368a3efb223097384a722436955bce0c44a1a5cffd0abb3164be0cce85ba0e9ebd9408166df3f1a95ea0c0d29e3a2534af2fae206c0419d67fde9
2 parents 2ddce35 + b193d5a commit 5924dad

File tree

8 files changed

+116
-10
lines changed

8 files changed

+116
-10
lines changed

src/netbase.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#include <fcntl.h>
2020
#endif
2121

22-
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
23-
2422
#if !defined(MSG_NOSIGNAL)
2523
#define MSG_NOSIGNAL 0
2624
#endif
@@ -37,7 +35,7 @@ static const int SOCKS5_RECV_TIMEOUT = 20 * 1000;
3735
static std::atomic<bool> interruptSocks5Recv(false);
3836

3937
enum Network ParseNetwork(std::string net) {
40-
boost::to_lower(net);
38+
Downcase(net);
4139
if (net == "ipv4") return NET_IPV4;
4240
if (net == "ipv6") return NET_IPV6;
4341
if (net == "onion") return NET_ONION;

src/rpc/server.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#include <boost/bind.hpp>
1818
#include <boost/signals2/signal.hpp>
19-
#include <boost/algorithm/string/case_conv.hpp> // for to_upper()
2019
#include <boost/algorithm/string/classification.hpp>
2120
#include <boost/algorithm/string/split.hpp>
2221

@@ -192,9 +191,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
192191
if (!category.empty())
193192
strRet += "\n";
194193
category = pcmd->category;
195-
std::string firstLetter = category.substr(0,1);
196-
boost::to_upper(firstLetter);
197-
strRet += "== " + firstLetter + category.substr(1) + " ==\n";
194+
strRet += "== " + Capitalize(category) + " ==\n";
198195
}
199196
}
200197
strRet += strHelp + "\n";

src/test/netbase_tests.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,4 +302,22 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup)
302302
BOOST_CHECK(CreateInternal("baz.net").GetGroup() == internal_group);
303303
}
304304

305+
BOOST_AUTO_TEST_CASE(netbase_parsenetwork)
306+
{
307+
BOOST_CHECK_EQUAL(ParseNetwork("ipv4"), NET_IPV4);
308+
BOOST_CHECK_EQUAL(ParseNetwork("ipv6"), NET_IPV6);
309+
BOOST_CHECK_EQUAL(ParseNetwork("onion"), NET_ONION);
310+
BOOST_CHECK_EQUAL(ParseNetwork("tor"), NET_ONION);
311+
312+
BOOST_CHECK_EQUAL(ParseNetwork("IPv4"), NET_IPV4);
313+
BOOST_CHECK_EQUAL(ParseNetwork("IPv6"), NET_IPV6);
314+
BOOST_CHECK_EQUAL(ParseNetwork("ONION"), NET_ONION);
315+
BOOST_CHECK_EQUAL(ParseNetwork("TOR"), NET_ONION);
316+
317+
BOOST_CHECK_EQUAL(ParseNetwork(":)"), NET_UNROUTABLE);
318+
BOOST_CHECK_EQUAL(ParseNetwork("tÖr"), NET_UNROUTABLE);
319+
BOOST_CHECK_EQUAL(ParseNetwork("\xfe\xff"), NET_UNROUTABLE);
320+
BOOST_CHECK_EQUAL(ParseNetwork(""), NET_UNROUTABLE);
321+
}
322+
305323
BOOST_AUTO_TEST_SUITE_END()

src/test/util_tests.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,4 +1217,43 @@ BOOST_AUTO_TEST_CASE(test_DirIsWritable)
12171217
fs::remove(tmpdirname);
12181218
}
12191219

1220+
BOOST_AUTO_TEST_CASE(test_ToLower)
1221+
{
1222+
BOOST_CHECK_EQUAL(ToLower('@'), '@');
1223+
BOOST_CHECK_EQUAL(ToLower('A'), 'a');
1224+
BOOST_CHECK_EQUAL(ToLower('Z'), 'z');
1225+
BOOST_CHECK_EQUAL(ToLower('['), '[');
1226+
BOOST_CHECK_EQUAL(ToLower(0), 0);
1227+
BOOST_CHECK_EQUAL(ToLower(255), 255);
1228+
1229+
std::string testVector;
1230+
Downcase(testVector);
1231+
BOOST_CHECK_EQUAL(testVector, "");
1232+
1233+
testVector = "#HODL";
1234+
Downcase(testVector);
1235+
BOOST_CHECK_EQUAL(testVector, "#hodl");
1236+
1237+
testVector = "\x00\xfe\xff";
1238+
Downcase(testVector);
1239+
BOOST_CHECK_EQUAL(testVector, "\x00\xfe\xff");
1240+
}
1241+
1242+
BOOST_AUTO_TEST_CASE(test_ToUpper)
1243+
{
1244+
BOOST_CHECK_EQUAL(ToUpper('`'), '`');
1245+
BOOST_CHECK_EQUAL(ToUpper('a'), 'A');
1246+
BOOST_CHECK_EQUAL(ToUpper('z'), 'Z');
1247+
BOOST_CHECK_EQUAL(ToUpper('{'), '{');
1248+
BOOST_CHECK_EQUAL(ToUpper(0), 0);
1249+
BOOST_CHECK_EQUAL(ToUpper(255), 255);
1250+
}
1251+
1252+
BOOST_AUTO_TEST_CASE(test_Capitalize)
1253+
{
1254+
BOOST_CHECK_EQUAL(Capitalize(""), "");
1255+
BOOST_CHECK_EQUAL(Capitalize("bitcoin"), "Bitcoin");
1256+
BOOST_CHECK_EQUAL(Capitalize("\x00\xfe\xff"), "\x00\xfe\xff");
1257+
}
1258+
12201259
BOOST_AUTO_TEST_SUITE_END()

src/utilstrencodings.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <tinyformat.h>
99

10+
#include <algorithm>
1011
#include <cstdlib>
1112
#include <cstring>
1213
#include <errno.h>
@@ -584,3 +585,15 @@ bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypa
584585
}
585586
return true;
586587
}
588+
589+
void Downcase(std::string& str)
590+
{
591+
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c){return ToLower(c);});
592+
}
593+
594+
std::string Capitalize(std::string str)
595+
{
596+
if (str.empty()) return str;
597+
str[0] = ToUpper(str.front());
598+
return str;
599+
}

src/utilstrencodings.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,4 +186,48 @@ bool ConvertBits(const O& outfn, I it, I end) {
186186
/** Parse an HD keypaths like "m/7/0'/2000". */
187187
bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath);
188188

189+
/**
190+
* Converts the given character to its lowercase equivalent.
191+
* This function is locale independent. It only converts uppercase
192+
* characters in the standard 7-bit ASCII range.
193+
* @param[in] c the character to convert to lowercase.
194+
* @return the lowercase equivalent of c; or the argument
195+
* if no conversion is possible.
196+
*/
197+
constexpr unsigned char ToLower(unsigned char c)
198+
{
199+
return (c >= 'A' && c <= 'Z' ? (c - 'A') + 'a' : c);
200+
}
201+
202+
/**
203+
* Converts the given string to its lowercase equivalent.
204+
* This function is locale independent. It only converts uppercase
205+
* characters in the standard 7-bit ASCII range.
206+
* @param[in,out] str the string to convert to lowercase.
207+
*/
208+
void Downcase(std::string& str);
209+
210+
/**
211+
* Converts the given character to its uppercase equivalent.
212+
* This function is locale independent. It only converts lowercase
213+
* characters in the standard 7-bit ASCII range.
214+
* @param[in] c the character to convert to uppercase.
215+
* @return the uppercase equivalent of c; or the argument
216+
* if no conversion is possible.
217+
*/
218+
constexpr unsigned char ToUpper(unsigned char c)
219+
{
220+
return (c >= 'a' && c <= 'z' ? (c - 'a') + 'A' : c);
221+
}
222+
223+
/**
224+
* Capitalizes the first character of the given string.
225+
* This function is locale independent. It only capitalizes the
226+
* first character of the argument if it has an uppercase equivalent
227+
* in the standard 7-bit ASCII range.
228+
* @param[in] str the string to capitalize.
229+
* @return string with the first letter capitalized.
230+
*/
231+
std::string Capitalize(std::string str);
232+
189233
#endif // BITCOIN_UTILSTRENCODINGS_H

test/lint/lint-includes.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ fi
4747

4848
EXPECTED_BOOST_INCLUDES=(
4949
boost/algorithm/string.hpp
50-
boost/algorithm/string/case_conv.hpp
5150
boost/algorithm/string/classification.hpp
5251
boost/algorithm/string/replace.hpp
5352
boost/algorithm/string/split.hpp

test/lint/lint-locale-dependence.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@ KNOWN_VIOLATIONS=(
1111
"src/dbwrapper.cpp:.*vsnprintf"
1212
"src/httprpc.cpp.*trim"
1313
"src/init.cpp:.*atoi"
14-
"src/netbase.cpp.*to_lower"
1514
"src/qt/rpcconsole.cpp:.*atoi"
1615
"src/qt/rpcconsole.cpp:.*isdigit"
1716
"src/rest.cpp:.*strtol"
18-
"src/rpc/server.cpp.*to_upper"
1917
"src/test/dbwrapper_tests.cpp:.*snprintf"
2018
"src/test/getarg_tests.cpp.*split"
2119
"src/torcontrol.cpp:.*atoi"

0 commit comments

Comments
 (0)