Skip to content

Commit 0ff7cd7

Browse files
author
MarcoFalke
committed
Merge #16889: Add some general std::vector utility functions
7d8d3e6 Add tests for util/vector.h's Cat and Vector (Pieter Wuille) e65e61c Add some general std::vector utility functions (Pieter Wuille) Pull request description: This is another general improvement extracted from #16800 . Two functions are added are: * Vector(arg1,arg2,arg3,...) constructs a vector with the specified arguments as elements. The vector's type is derived from the arguments. If some of the arguments are rvalue references, they will be moved into place rather than copied (which can't be achieved using list initialization). * Cat(vector1,vector2) returns a concatenation of the two vectors, efficiently moving elements when relevant. Vector generalizes (and replaces) the `Singleton` function in src/descriptor.cpp, and `Cat` replaces the function in bech32.cpp ACKs for top commit: laanwj: ACK 7d8d3e6 MarcoFalke: ACK 7d8d3e6 (enjoyed reading the tests, but did not compile) Tree-SHA512: 92325f14e90d7e7d9d920421979aec22bb0d730e0291362b4326cccc76f9c2d865bec33a797c5c0201773468c3773cb50ce52c8eee4c1ec1a4d10db5cf2b9d2a
2 parents f2a0948 + 7d8d3e6 commit 0ff7cd7

File tree

7 files changed

+179
-32
lines changed

7 files changed

+179
-32
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ BITCOIN_CORE_H = \
220220
util/translation.h \
221221
util/url.h \
222222
util/validation.h \
223+
util/vector.h \
223224
validation.h \
224225
validationinterface.h \
225226
versionbits.h \

src/bech32.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

55
#include <bech32.h>
6+
#include <util/vector.h>
67

78
#include <assert.h>
89

@@ -26,13 +27,6 @@ const int8_t CHARSET_REV[128] = {
2627
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
2728
};
2829

29-
/** Concatenate two byte arrays. */
30-
data Cat(data x, const data& y)
31-
{
32-
x.insert(x.end(), y.begin(), y.end());
33-
return x;
34-
}
35-
3630
/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
3731
* make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
3832
* bits correspond to earlier values. */

src/outputtype.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <script/sign.h>
1111
#include <script/signingprovider.h>
1212
#include <script/standard.h>
13+
#include <util/vector.h>
1314

1415
#include <assert.h>
1516
#include <string>
@@ -65,12 +66,13 @@ CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
6566
std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
6667
{
6768
PKHash keyid(key);
69+
CTxDestination p2pkh{keyid};
6870
if (key.IsCompressed()) {
6971
CTxDestination segwit = WitnessV0KeyHash(keyid);
7072
CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit));
71-
return std::vector<CTxDestination>{std::move(keyid), std::move(p2sh), std::move(segwit)};
73+
return Vector(std::move(p2pkh), std::move(p2sh), std::move(segwit));
7274
} else {
73-
return std::vector<CTxDestination>{std::move(keyid)};
75+
return Vector(std::move(p2pkh));
7476
}
7577
}
7678

src/script/descriptor.cpp

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <util/spanparsing.h>
1515
#include <util/system.h>
1616
#include <util/strencodings.h>
17+
#include <util/vector.h>
1718

1819
#include <memory>
1920
#include <string>
@@ -501,22 +502,13 @@ class DescriptorImpl : public Descriptor
501502
}
502503
};
503504

504-
/** Construct a vector with one element, which is moved into it. */
505-
template<typename T>
506-
std::vector<T> Singleton(T elem)
507-
{
508-
std::vector<T> ret;
509-
ret.emplace_back(std::move(elem));
510-
return ret;
511-
}
512-
513505
/** A parsed addr(A) descriptor. */
514506
class AddressDescriptor final : public DescriptorImpl
515507
{
516508
const CTxDestination m_destination;
517509
protected:
518510
std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
519-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(m_destination)); }
511+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
520512
public:
521513
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
522514
bool IsSolvable() const final { return false; }
@@ -528,7 +520,7 @@ class RawDescriptor final : public DescriptorImpl
528520
const CScript m_script;
529521
protected:
530522
std::string ToStringExtra() const override { return HexStr(m_script.begin(), m_script.end()); }
531-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Singleton(m_script); }
523+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); }
532524
public:
533525
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
534526
bool IsSolvable() const final { return false; }
@@ -538,9 +530,9 @@ class RawDescriptor final : public DescriptorImpl
538530
class PKDescriptor final : public DescriptorImpl
539531
{
540532
protected:
541-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForRawPubKey(keys[0])); }
533+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
542534
public:
543-
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pk") {}
535+
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pk") {}
544536
};
545537

546538
/** A parsed pkh(P) descriptor. */
@@ -551,10 +543,10 @@ class PKHDescriptor final : public DescriptorImpl
551543
{
552544
CKeyID id = keys[0].GetID();
553545
out.pubkeys.emplace(id, keys[0]);
554-
return Singleton(GetScriptForDestination(PKHash(id)));
546+
return Vector(GetScriptForDestination(PKHash(id)));
555547
}
556548
public:
557-
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {}
549+
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {}
558550
};
559551

560552
/** A parsed wpkh(P) descriptor. */
@@ -565,10 +557,10 @@ class WPKHDescriptor final : public DescriptorImpl
565557
{
566558
CKeyID id = keys[0].GetID();
567559
out.pubkeys.emplace(id, keys[0]);
568-
return Singleton(GetScriptForDestination(WitnessV0KeyHash(id)));
560+
return Vector(GetScriptForDestination(WitnessV0KeyHash(id)));
569561
}
570562
public:
571-
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "wpkh") {}
563+
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "wpkh") {}
572564
};
573565

574566
/** A parsed combo(P) descriptor. */
@@ -591,7 +583,7 @@ class ComboDescriptor final : public DescriptorImpl
591583
return ret;
592584
}
593585
public:
594-
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "combo") {}
586+
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "combo") {}
595587
};
596588

597589
/** A parsed multi(...) or sortedmulti(...) descriptor */
@@ -605,9 +597,9 @@ class MultisigDescriptor final : public DescriptorImpl
605597
if (m_sorted) {
606598
std::vector<CPubKey> sorted_keys(keys);
607599
std::sort(sorted_keys.begin(), sorted_keys.end());
608-
return Singleton(GetScriptForMultisig(m_threshold, sorted_keys));
600+
return Vector(GetScriptForMultisig(m_threshold, sorted_keys));
609601
}
610-
return Singleton(GetScriptForMultisig(m_threshold, keys));
602+
return Vector(GetScriptForMultisig(m_threshold, keys));
611603
}
612604
public:
613605
MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), {}, sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
@@ -617,7 +609,7 @@ class MultisigDescriptor final : public DescriptorImpl
617609
class SHDescriptor final : public DescriptorImpl
618610
{
619611
protected:
620-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(ScriptHash(*script))); }
612+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(ScriptHash(*script))); }
621613
public:
622614
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
623615
};
@@ -626,7 +618,7 @@ class SHDescriptor final : public DescriptorImpl
626618
class WSHDescriptor final : public DescriptorImpl
627619
{
628620
protected:
629-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(WitnessV0ScriptHash(*script))); }
621+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(WitnessV0ScriptHash(*script))); }
630622
public:
631623
WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
632624
};

src/test/util_tests.cpp

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <util/string.h>
1414
#include <util/time.h>
1515
#include <util/spanparsing.h>
16+
#include <util/vector.h>
1617

1718
#include <stdint.h>
1819
#include <thread>
@@ -1714,4 +1715,109 @@ BOOST_AUTO_TEST_CASE(test_LogEscapeMessage)
17141715
BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage(NUL), R"(O\x00O)");
17151716
}
17161717

1718+
namespace {
1719+
1720+
struct Tracker
1721+
{
1722+
//! Points to the original object (possibly itself) we moved/copied from
1723+
const Tracker* origin;
1724+
//! How many copies where involved between the original object and this one (moves are not counted)
1725+
int copies;
1726+
1727+
Tracker() noexcept : origin(this), copies(0) {}
1728+
Tracker(const Tracker& t) noexcept : origin(t.origin), copies(t.copies + 1) {}
1729+
Tracker(Tracker&& t) noexcept : origin(t.origin), copies(t.copies) {}
1730+
Tracker& operator=(const Tracker& t) noexcept
1731+
{
1732+
origin = t.origin;
1733+
copies = t.copies + 1;
1734+
return *this;
1735+
}
1736+
Tracker& operator=(Tracker&& t) noexcept
1737+
{
1738+
origin = t.origin;
1739+
copies = t.copies;
1740+
return *this;
1741+
}
1742+
};
1743+
1744+
}
1745+
1746+
BOOST_AUTO_TEST_CASE(test_tracked_vector)
1747+
{
1748+
Tracker t1;
1749+
Tracker t2;
1750+
Tracker t3;
1751+
1752+
BOOST_CHECK(t1.origin == &t1);
1753+
BOOST_CHECK(t2.origin == &t2);
1754+
BOOST_CHECK(t3.origin == &t3);
1755+
1756+
auto v1 = Vector(t1);
1757+
BOOST_CHECK_EQUAL(v1.size(), 1);
1758+
BOOST_CHECK(v1[0].origin == &t1);
1759+
BOOST_CHECK_EQUAL(v1[0].copies, 1);
1760+
1761+
auto v2 = Vector(std::move(t2));
1762+
BOOST_CHECK_EQUAL(v2.size(), 1);
1763+
BOOST_CHECK(v2[0].origin == &t2);
1764+
BOOST_CHECK_EQUAL(v2[0].copies, 0);
1765+
1766+
auto v3 = Vector(t1, std::move(t2));
1767+
BOOST_CHECK_EQUAL(v3.size(), 2);
1768+
BOOST_CHECK(v3[0].origin == &t1);
1769+
BOOST_CHECK(v3[1].origin == &t2);
1770+
BOOST_CHECK_EQUAL(v3[0].copies, 1);
1771+
BOOST_CHECK_EQUAL(v3[1].copies, 0);
1772+
1773+
auto v4 = Vector(std::move(v3[0]), v3[1], std::move(t3));
1774+
BOOST_CHECK_EQUAL(v4.size(), 3);
1775+
BOOST_CHECK(v4[0].origin == &t1);
1776+
BOOST_CHECK(v4[1].origin == &t2);
1777+
BOOST_CHECK(v4[2].origin == &t3);
1778+
BOOST_CHECK_EQUAL(v4[0].copies, 1);
1779+
BOOST_CHECK_EQUAL(v4[1].copies, 1);
1780+
BOOST_CHECK_EQUAL(v4[2].copies, 0);
1781+
1782+
auto v5 = Cat(v1, v4);
1783+
BOOST_CHECK_EQUAL(v5.size(), 4);
1784+
BOOST_CHECK(v5[0].origin == &t1);
1785+
BOOST_CHECK(v5[1].origin == &t1);
1786+
BOOST_CHECK(v5[2].origin == &t2);
1787+
BOOST_CHECK(v5[3].origin == &t3);
1788+
BOOST_CHECK_EQUAL(v5[0].copies, 2);
1789+
BOOST_CHECK_EQUAL(v5[1].copies, 2);
1790+
BOOST_CHECK_EQUAL(v5[2].copies, 2);
1791+
BOOST_CHECK_EQUAL(v5[3].copies, 1);
1792+
1793+
auto v6 = Cat(std::move(v1), v3);
1794+
BOOST_CHECK_EQUAL(v6.size(), 3);
1795+
BOOST_CHECK(v6[0].origin == &t1);
1796+
BOOST_CHECK(v6[1].origin == &t1);
1797+
BOOST_CHECK(v6[2].origin == &t2);
1798+
BOOST_CHECK_EQUAL(v6[0].copies, 1);
1799+
BOOST_CHECK_EQUAL(v6[1].copies, 2);
1800+
BOOST_CHECK_EQUAL(v6[2].copies, 1);
1801+
1802+
auto v7 = Cat(v2, std::move(v4));
1803+
BOOST_CHECK_EQUAL(v7.size(), 4);
1804+
BOOST_CHECK(v7[0].origin == &t2);
1805+
BOOST_CHECK(v7[1].origin == &t1);
1806+
BOOST_CHECK(v7[2].origin == &t2);
1807+
BOOST_CHECK(v7[3].origin == &t3);
1808+
BOOST_CHECK_EQUAL(v7[0].copies, 1);
1809+
BOOST_CHECK_EQUAL(v7[1].copies, 1);
1810+
BOOST_CHECK_EQUAL(v7[2].copies, 1);
1811+
BOOST_CHECK_EQUAL(v7[3].copies, 0);
1812+
1813+
auto v8 = Cat(std::move(v2), std::move(v3));
1814+
BOOST_CHECK_EQUAL(v8.size(), 3);
1815+
BOOST_CHECK(v8[0].origin == &t2);
1816+
BOOST_CHECK(v8[1].origin == &t1);
1817+
BOOST_CHECK(v8[2].origin == &t2);
1818+
BOOST_CHECK_EQUAL(v8[0].copies, 0);
1819+
BOOST_CHECK_EQUAL(v8[1].copies, 1);
1820+
BOOST_CHECK_EQUAL(v8[2].copies, 0);
1821+
}
1822+
17171823
BOOST_AUTO_TEST_SUITE_END()

src/txdb.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <uint256.h>
1313
#include <util/system.h>
1414
#include <util/translation.h>
15+
#include <util/vector.h>
1516

1617
#include <stdint.h>
1718

@@ -102,7 +103,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
102103
// A vector is used for future extensibility, as we may want to support
103104
// interrupting after partial writes from multiple independent reorgs.
104105
batch.Erase(DB_BEST_BLOCK);
105-
batch.Write(DB_HEAD_BLOCKS, std::vector<uint256>{hashBlock, old_tip});
106+
batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
106107

107108
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
108109
if (it->second.flags & CCoinsCacheEntry::DIRTY) {

src/util/vector.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) 2019 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_VECTOR_H
6+
#define BITCOIN_UTIL_VECTOR_H
7+
8+
#include <initializer_list>
9+
#include <type_traits>
10+
#include <vector>
11+
12+
/** Construct a vector with the specified elements.
13+
*
14+
* This is preferable over the list initializing constructor of std::vector:
15+
* - It automatically infers the element type from its arguments.
16+
* - If any arguments are rvalue references, they will be moved into the vector
17+
* (list initialization always copies).
18+
*/
19+
template<typename... Args>
20+
inline std::vector<typename std::common_type<Args...>::type> Vector(Args&&... args)
21+
{
22+
std::vector<typename std::common_type<Args...>::type> ret;
23+
ret.reserve(sizeof...(args));
24+
// The line below uses the trick from https://www.experts-exchange.com/articles/32502/None-recursive-variadic-templates-with-std-initializer-list.html
25+
(void)std::initializer_list<int>{(ret.emplace_back(std::forward<Args>(args)), 0)...};
26+
return ret;
27+
}
28+
29+
/** Concatenate two vectors, moving elements. */
30+
template<typename V>
31+
inline V Cat(V v1, V&& v2)
32+
{
33+
v1.reserve(v1.size() + v2.size());
34+
for (auto& arg : v2) {
35+
v1.push_back(std::move(arg));
36+
}
37+
return v1;
38+
}
39+
40+
/** Concatenate two vectors. */
41+
template<typename V>
42+
inline V Cat(V v1, const V& v2)
43+
{
44+
v1.reserve(v1.size() + v2.size());
45+
for (const auto& arg : v2) {
46+
v1.push_back(arg);
47+
}
48+
return v1;
49+
}
50+
51+
#endif // BITCOIN_UTIL_VECTOR_H

0 commit comments

Comments
 (0)