Skip to content

Commit

Permalink
merge bitcoin#22953: introduce single-separator split helper
Browse files Browse the repository at this point in the history
  • Loading branch information
kwvg committed Jan 19, 2023
1 parent 39ee56a commit 135bfde
Show file tree
Hide file tree
Showing 14 changed files with 96 additions and 77 deletions.
17 changes: 5 additions & 12 deletions src/bitcoin-tx.cpp
Expand Up @@ -27,8 +27,6 @@
#include <memory>
#include <stdio.h>

#include <boost/algorithm/string.hpp>

#include <stacktraces.h>

static bool fCreateBlank;
Expand Down Expand Up @@ -215,8 +213,7 @@ static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)

static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
{
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
std::vector<std::string> vStrInputParts = SplitString(strInput, ':');

// separate TXID:VOUT in string
if (vStrInputParts.size()<2)
Expand Down Expand Up @@ -250,8 +247,7 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput)
{
// Separate into VALUE:ADDRESS
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
std::vector<std::string> vStrInputParts = SplitString(strInput, ':');

if (vStrInputParts.size() != 2)
throw std::runtime_error("TX output missing or too many separators");
Expand All @@ -275,8 +271,7 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput)
{
// Separate into VALUE:PUBKEY[:FLAGS]
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
std::vector<std::string> vStrInputParts = SplitString(strInput, ':');

if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3)
throw std::runtime_error("TX output missing or too many separators");
Expand Down Expand Up @@ -310,8 +305,7 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput)
{
// Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
std::vector<std::string> vStrInputParts = SplitString(strInput, ':');

// Check that there are enough parameters
if (vStrInputParts.size()<3)
Expand Down Expand Up @@ -400,8 +394,7 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn
static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput)
{
// separate VALUE:SCRIPT[:FLAGS]
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
if (vStrInputParts.size() < 2)
throw std::runtime_error("TX output missing separator");

Expand Down
21 changes: 6 additions & 15 deletions src/chainparams.cpp
Expand Up @@ -18,9 +18,6 @@

#include <assert.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>

static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
CMutableTransaction txNew;
Expand Down Expand Up @@ -1112,8 +1109,7 @@ void CRegTestParams::UpdateVersionBitsParametersFromArgs(const ArgsManager& args
if (!args.IsArgSet("-vbparams")) return;

for (const std::string& strDeployment : args.GetArgs("-vbparams")) {
std::vector<std::string> vDeploymentParams;
boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":"));
std::vector<std::string> vDeploymentParams = SplitString(strDeployment, ':');
if (vDeploymentParams.size() != 3 && vDeploymentParams.size() != 5 && vDeploymentParams.size() != 7) {
throw std::runtime_error("Version bits parameters malformed, expecting "
"<deployment>:<start>:<end> or "
Expand Down Expand Up @@ -1164,8 +1160,7 @@ void CRegTestParams::UpdateDIP3ParametersFromArgs(const ArgsManager& args)
if (!args.IsArgSet("-dip3params")) return;

std::string strParams = args.GetArg("-dip3params", "");
std::vector<std::string> vParams;
boost::split(vParams, strParams, boost::is_any_of(":"));
std::vector<std::string> vParams = SplitString(strParams, ':');
if (vParams.size() != 2) {
throw std::runtime_error("DIP3 parameters malformed, expecting <activation>:<enforcement>");
}
Expand All @@ -1185,8 +1180,7 @@ void CRegTestParams::UpdateDIP8ParametersFromArgs(const ArgsManager& args)
if (!args.IsArgSet("-dip8params")) return;

std::string strParams = args.GetArg("-dip8params", "");
std::vector<std::string> vParams;
boost::split(vParams, strParams, boost::is_any_of(":"));
std::vector<std::string> vParams = SplitString(strParams, ':');
if (vParams.size() != 1) {
throw std::runtime_error("DIP8 parameters malformed, expecting <activation>");
}
Expand All @@ -1203,8 +1197,7 @@ void CRegTestParams::UpdateBudgetParametersFromArgs(const ArgsManager& args)
if (!args.IsArgSet("-budgetparams")) return;

std::string strParams = args.GetArg("-budgetparams", "");
std::vector<std::string> vParams;
boost::split(vParams, strParams, boost::is_any_of(":"));
std::vector<std::string> vParams = SplitString(strParams, ':');
if (vParams.size() != 3) {
throw std::runtime_error("Budget parameters malformed, expecting <masternode>:<budget>:<superblock>");
}
Expand Down Expand Up @@ -1235,8 +1228,7 @@ void CRegTestParams::UpdateLLMQTestParametersFromArgs(const ArgsManager& args, c
if (!args.IsArgSet(cmd_param)) return;

std::string strParams = args.GetArg(cmd_param, "");
std::vector<std::string> vParams;
boost::split(vParams, strParams, boost::is_any_of(":"));
std::vector<std::string> vParams = SplitString(strParams, ':');
if (vParams.size() != 2) {
throw std::runtime_error(strprintf("%s parameters malformed, expecting <size>:<threshold>", llmq_name));
}
Expand Down Expand Up @@ -1352,8 +1344,7 @@ void CDevNetParams::UpdateLLMQDevnetParametersFromArgs(const ArgsManager& args)
if (!args.IsArgSet("-llmqdevnetparams")) return;

std::string strParams = args.GetArg("-llmqdevnetparams", "");
std::vector<std::string> vParams;
boost::split(vParams, strParams, boost::is_any_of(":"));
std::vector<std::string> vParams = SplitString(strParams, ':');
if (vParams.size() != 2) {
throw std::runtime_error("LLMQ_DEVNET parameters malformed, expecting <size>:<threshold>");
}
Expand Down
7 changes: 2 additions & 5 deletions src/rest.cpp
Expand Up @@ -25,8 +25,6 @@
#include <validation.h>
#include <version.h>

#include <boost/algorithm/string.hpp>

#include <univalue.h>

static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once
Expand Down Expand Up @@ -162,8 +160,7 @@ static bool rest_headers(const CoreContext& context,
return false;
std::string param;
const RetFormat rf = ParseDataFormat(param, strURIPart);
std::vector<std::string> path;
boost::split(path, param, boost::is_any_of("/"));
std::vector<std::string> path = SplitString(param, '/');

if (path.size() != 2)
return RESTERR(req, HTTP_BAD_REQUEST, "No header count specified. Use /rest/headers/<count>/<hash>.<ext>.");
Expand Down Expand Up @@ -449,7 +446,7 @@ static bool rest_getutxos(const CoreContext& context, HTTPRequest* req, const st
if (param.length() > 1)
{
std::string strUriParams = param.substr(1);
boost::split(uriParts, strUriParams, boost::is_any_of("/"));
uriParts = SplitString(strUriParams, '/');
}

// throw exception in case of an empty request
Expand Down
6 changes: 1 addition & 5 deletions src/rpc/misc.cpp
Expand Up @@ -35,8 +35,6 @@
#include <malloc.h>
#endif

#include <boost/algorithm/string.hpp>

#include <univalue.h>

static UniValue debug(const JSONRPCRequest& request)
Expand Down Expand Up @@ -64,9 +62,7 @@ static UniValue debug(const JSONRPCRequest& request)
std::string strMode = request.params[0].get_str();
LogInstance().DisableCategory(BCLog::ALL);

std::vector<std::string> categories;
boost::split(categories, strMode, boost::is_any_of("+"));

std::vector<std::string> categories = SplitString(strMode, '+');
if (std::find(categories.begin(), categories.end(), std::string("0")) == categories.end()) {
for (const auto& cat : categories) {
LogInstance().EnableCategory(cat);
Expand Down
6 changes: 2 additions & 4 deletions src/rpc/server.cpp
Expand Up @@ -11,10 +11,9 @@
#include <shutdown.h>
#include <sync.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/system.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/signals2/signal.hpp>

#include <algorithm>
Expand Down Expand Up @@ -424,8 +423,7 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
// Process expected parameters.
int hole = 0;
for (const std::string &argNamePattern: argNames) {
std::vector<std::string> vargNames;
boost::algorithm::split(vargNames, argNamePattern, boost::algorithm::is_any_of("|"));
std::vector<std::string> vargNames = SplitString(argNamePattern, '|');
auto fr = argsIn.end();
for (const std::string & argName : vargNames) {
fr = argsIn.find(argName);
Expand Down
6 changes: 1 addition & 5 deletions src/rpc/util.cpp
Expand Up @@ -16,9 +16,6 @@

#include <tuple>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>

const std::string UNIX_EPOCH_TIME = "UNIX epoch time";


Expand Down Expand Up @@ -408,8 +405,7 @@ RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RP
{
std::set<std::string> named_args;
for (const auto& arg : m_args) {
std::vector<std::string> names;
boost::split(names, arg.m_names, boost::is_any_of("|"));
std::vector<std::string> names = SplitString(arg.m_names, '|');
// Should have unique named arguments
for (const std::string& name : names) {
CHECK_NONFATAL(named_args.insert(name).second);
Expand Down
1 change: 1 addition & 0 deletions src/test/fuzz/string.cpp
Expand Up @@ -217,6 +217,7 @@ FUZZ_TARGET(string)
int64_t amount_out;
(void)ParseFixedPoint(random_string_1, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 1024), &amount_out);
}
(void)SplitString(random_string_1, fuzzed_data_provider.ConsumeIntegral<char>());
{
(void)Untranslated(random_string_1);
const bilingual_str bs1{random_string_1, random_string_2};
Expand Down
5 changes: 1 addition & 4 deletions src/test/transaction_tests.cpp
Expand Up @@ -24,8 +24,6 @@
#include <map>
#include <string>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/test/unit_test.hpp>

#include <univalue.h>
Expand Down Expand Up @@ -57,8 +55,7 @@ unsigned int ParseScriptFlags(std::string strFlags)
return 0;
}
unsigned int flags = 0;
std::vector<std::string> words;
boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(","));
std::vector<std::string> words = SplitString(strFlags, ',');

for (const std::string& word : words)
{
Expand Down
49 changes: 49 additions & 0 deletions src/test/util_tests.cpp
Expand Up @@ -2116,6 +2116,55 @@ BOOST_AUTO_TEST_CASE(test_spanparsing)
BOOST_CHECK_EQUAL(SpanToStr(results[3]), "");
}

BOOST_AUTO_TEST_CASE(test_SplitString)
{
// Empty string.
{
std::vector<std::string> result = SplitString("", '-');
BOOST_CHECK_EQUAL(result.size(), 1);
BOOST_CHECK_EQUAL(result[0], "");
}

// Empty items.
{
std::vector<std::string> result = SplitString("-", '-');
BOOST_CHECK_EQUAL(result.size(), 2);
BOOST_CHECK_EQUAL(result[0], "");
BOOST_CHECK_EQUAL(result[1], "");
}

// More empty items.
{
std::vector<std::string> result = SplitString("--", '-');
BOOST_CHECK_EQUAL(result.size(), 3);
BOOST_CHECK_EQUAL(result[0], "");
BOOST_CHECK_EQUAL(result[1], "");
BOOST_CHECK_EQUAL(result[2], "");
}

// Separator is not present.
{
std::vector<std::string> result = SplitString("abc", '-');
BOOST_CHECK_EQUAL(result.size(), 1);
BOOST_CHECK_EQUAL(result[0], "abc");
}

// Basic behavior.
{
std::vector<std::string> result = SplitString("a-b", '-');
BOOST_CHECK_EQUAL(result.size(), 2);
BOOST_CHECK_EQUAL(result[0], "a");
BOOST_CHECK_EQUAL(result[1], "b");
}

// Case-sensitivity of the separator.
{
std::vector<std::string> result = SplitString("AAA", 'a');
BOOST_CHECK_EQUAL(result.size(), 1);
BOOST_CHECK_EQUAL(result[0], "AAA");
}
}

BOOST_AUTO_TEST_CASE(test_LogEscapeMessage)
{
// ASCII and UTF-8 must pass through unaltered.
Expand Down
8 changes: 4 additions & 4 deletions src/torcontrol.cpp
Expand Up @@ -18,8 +18,6 @@
#include <stdlib.h>

#include <boost/signals2/signal.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>

#include <event2/bufferevent.h>
Expand Down Expand Up @@ -622,8 +620,10 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
if (l.first == "AUTH") {
std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);
std::map<std::string,std::string>::iterator i;
if ((i = m.find("METHODS")) != m.end())
boost::split(methods, i->second, boost::is_any_of(","));
if ((i = m.find("METHODS")) != m.end()) {
std::vector<std::string> m_vec = SplitString(i->second, ',');
methods = std::set<std::string>(m_vec.begin(), m_vec.end());
}
if ((i = m.find("COOKIEFILE")) != m.end())
cookiefile = i->second;
} else if (l.first == "VERSION") {
Expand Down
16 changes: 0 additions & 16 deletions src/util/spanparsing.cpp
Expand Up @@ -48,20 +48,4 @@ Span<const char> Expr(Span<const char>& sp)
return ret;
}

std::vector<Span<const char>> Split(const Span<const char>& sp, char sep)
{
std::vector<Span<const char>> ret;
auto it = sp.begin();
auto start = it;
while (it != sp.end()) {
if (*it == sep) {
ret.emplace_back(start, it);
start = it + 1;
}
++it;
}
ret.emplace_back(start, it);
return ret;
}

} // namespace spanparsing
17 changes: 16 additions & 1 deletion src/util/spanparsing.h
Expand Up @@ -43,7 +43,22 @@ Span<const char> Expr(Span<const char>& sp);
* Note that this function does not care about braces, so splitting
* "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}.
*/
std::vector<Span<const char>> Split(const Span<const char>& sp, char sep);
template <typename T = Span<const char>>
std::vector<T> Split(const Span<const char>& sp, char sep)
{
std::vector<T> ret;
auto it = sp.begin();
auto start = it;
while (it != sp.end()) {
if (*it == sep) {
ret.emplace_back(start, it);
start = it + 1;
}
++it;
}
ret.emplace_back(start, it);
return ret;
}

} // namespace spanparsing

Expand Down
6 changes: 6 additions & 0 deletions src/util/string.h
Expand Up @@ -6,6 +6,7 @@
#define BITCOIN_UTIL_STRING_H

#include <attributes.h>
#include <util/spanparsing.h>

#include <algorithm>
#include <array>
Expand All @@ -15,6 +16,11 @@
#include <string>
#include <vector>

[[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep)
{
return spanparsing::Split<std::string>(str, sep);
}

[[nodiscard]] inline std::string TrimString(const std::string& str, const std::string& pattern = " \f\n\r\t\v")
{
std::string::size_type front = str.find_first_not_of(pattern);
Expand Down

0 comments on commit 135bfde

Please sign in to comment.