Merge #16889: Add some general std::vector utility functions
7d8d3e6a2a
Add tests for util/vector.h's Cat and Vector (Pieter Wuille)e65e61c812
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: ACK7d8d3e6a2a
MarcoFalke: ACK7d8d3e6a2a
(enjoyed reading the tests, but did not compile) Tree-SHA512: 92325f14e90d7e7d9d920421979aec22bb0d730e0291362b4326cccc76f9c2d865bec33a797c5c0201773468c3773cb50ce52c8eee4c1ec1a4d10db5cf2b9d2a
This commit is contained in:
commit
0ff7cd7d0c
7 changed files with 179 additions and 32 deletions
|
@ -220,6 +220,7 @@ BITCOIN_CORE_H = \
|
||||||
util/translation.h \
|
util/translation.h \
|
||||||
util/url.h \
|
util/url.h \
|
||||||
util/validation.h \
|
util/validation.h \
|
||||||
|
util/vector.h \
|
||||||
validation.h \
|
validation.h \
|
||||||
validationinterface.h \
|
validationinterface.h \
|
||||||
versionbits.h \
|
versionbits.h \
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include <bech32.h>
|
#include <bech32.h>
|
||||||
|
#include <util/vector.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
@ -26,13 +27,6 @@ const int8_t CHARSET_REV[128] = {
|
||||||
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
|
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Concatenate two byte arrays. */
|
|
||||||
data Cat(data x, const data& y)
|
|
||||||
{
|
|
||||||
x.insert(x.end(), y.begin(), y.end());
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
|
/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
|
||||||
* make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
|
* make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
|
||||||
* bits correspond to earlier values. */
|
* bits correspond to earlier values. */
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <script/sign.h>
|
#include <script/sign.h>
|
||||||
#include <script/signingprovider.h>
|
#include <script/signingprovider.h>
|
||||||
#include <script/standard.h>
|
#include <script/standard.h>
|
||||||
|
#include <util/vector.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -65,12 +66,13 @@ CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
|
||||||
std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
|
std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
|
||||||
{
|
{
|
||||||
PKHash keyid(key);
|
PKHash keyid(key);
|
||||||
|
CTxDestination p2pkh{keyid};
|
||||||
if (key.IsCompressed()) {
|
if (key.IsCompressed()) {
|
||||||
CTxDestination segwit = WitnessV0KeyHash(keyid);
|
CTxDestination segwit = WitnessV0KeyHash(keyid);
|
||||||
CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit));
|
CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit));
|
||||||
return std::vector<CTxDestination>{std::move(keyid), std::move(p2sh), std::move(segwit)};
|
return Vector(std::move(p2pkh), std::move(p2sh), std::move(segwit));
|
||||||
} else {
|
} else {
|
||||||
return std::vector<CTxDestination>{std::move(keyid)};
|
return Vector(std::move(p2pkh));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <util/spanparsing.h>
|
#include <util/spanparsing.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
|
#include <util/vector.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -501,22 +502,13 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Construct a vector with one element, which is moved into it. */
|
|
||||||
template<typename T>
|
|
||||||
std::vector<T> Singleton(T elem)
|
|
||||||
{
|
|
||||||
std::vector<T> ret;
|
|
||||||
ret.emplace_back(std::move(elem));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A parsed addr(A) descriptor. */
|
/** A parsed addr(A) descriptor. */
|
||||||
class AddressDescriptor final : public DescriptorImpl
|
class AddressDescriptor final : public DescriptorImpl
|
||||||
{
|
{
|
||||||
const CTxDestination m_destination;
|
const CTxDestination m_destination;
|
||||||
protected:
|
protected:
|
||||||
std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
|
std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(m_destination)); }
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
|
||||||
public:
|
public:
|
||||||
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
|
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
|
||||||
bool IsSolvable() const final { return false; }
|
bool IsSolvable() const final { return false; }
|
||||||
|
@ -528,7 +520,7 @@ class RawDescriptor final : public DescriptorImpl
|
||||||
const CScript m_script;
|
const CScript m_script;
|
||||||
protected:
|
protected:
|
||||||
std::string ToStringExtra() const override { return HexStr(m_script.begin(), m_script.end()); }
|
std::string ToStringExtra() const override { return HexStr(m_script.begin(), m_script.end()); }
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Singleton(m_script); }
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); }
|
||||||
public:
|
public:
|
||||||
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
|
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
|
||||||
bool IsSolvable() const final { return false; }
|
bool IsSolvable() const final { return false; }
|
||||||
|
@ -538,9 +530,9 @@ public:
|
||||||
class PKDescriptor final : public DescriptorImpl
|
class PKDescriptor final : public DescriptorImpl
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForRawPubKey(keys[0])); }
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
|
||||||
public:
|
public:
|
||||||
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pk") {}
|
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pk") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A parsed pkh(P) descriptor. */
|
/** A parsed pkh(P) descriptor. */
|
||||||
|
@ -551,10 +543,10 @@ protected:
|
||||||
{
|
{
|
||||||
CKeyID id = keys[0].GetID();
|
CKeyID id = keys[0].GetID();
|
||||||
out.pubkeys.emplace(id, keys[0]);
|
out.pubkeys.emplace(id, keys[0]);
|
||||||
return Singleton(GetScriptForDestination(PKHash(id)));
|
return Vector(GetScriptForDestination(PKHash(id)));
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {}
|
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A parsed wpkh(P) descriptor. */
|
/** A parsed wpkh(P) descriptor. */
|
||||||
|
@ -565,10 +557,10 @@ protected:
|
||||||
{
|
{
|
||||||
CKeyID id = keys[0].GetID();
|
CKeyID id = keys[0].GetID();
|
||||||
out.pubkeys.emplace(id, keys[0]);
|
out.pubkeys.emplace(id, keys[0]);
|
||||||
return Singleton(GetScriptForDestination(WitnessV0KeyHash(id)));
|
return Vector(GetScriptForDestination(WitnessV0KeyHash(id)));
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "wpkh") {}
|
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "wpkh") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A parsed combo(P) descriptor. */
|
/** A parsed combo(P) descriptor. */
|
||||||
|
@ -591,7 +583,7 @@ protected:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "combo") {}
|
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "combo") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A parsed multi(...) or sortedmulti(...) descriptor */
|
/** A parsed multi(...) or sortedmulti(...) descriptor */
|
||||||
|
@ -605,9 +597,9 @@ protected:
|
||||||
if (m_sorted) {
|
if (m_sorted) {
|
||||||
std::vector<CPubKey> sorted_keys(keys);
|
std::vector<CPubKey> sorted_keys(keys);
|
||||||
std::sort(sorted_keys.begin(), sorted_keys.end());
|
std::sort(sorted_keys.begin(), sorted_keys.end());
|
||||||
return Singleton(GetScriptForMultisig(m_threshold, sorted_keys));
|
return Vector(GetScriptForMultisig(m_threshold, sorted_keys));
|
||||||
}
|
}
|
||||||
return Singleton(GetScriptForMultisig(m_threshold, keys));
|
return Vector(GetScriptForMultisig(m_threshold, keys));
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
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) {}
|
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 @@ public:
|
||||||
class SHDescriptor final : public DescriptorImpl
|
class SHDescriptor final : public DescriptorImpl
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(ScriptHash(*script))); }
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(ScriptHash(*script))); }
|
||||||
public:
|
public:
|
||||||
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
|
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
|
||||||
};
|
};
|
||||||
|
@ -626,7 +618,7 @@ public:
|
||||||
class WSHDescriptor final : public DescriptorImpl
|
class WSHDescriptor final : public DescriptorImpl
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(WitnessV0ScriptHash(*script))); }
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(WitnessV0ScriptHash(*script))); }
|
||||||
public:
|
public:
|
||||||
WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
|
WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <util/time.h>
|
#include <util/time.h>
|
||||||
#include <util/spanparsing.h>
|
#include <util/spanparsing.h>
|
||||||
|
#include <util/vector.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
@ -1714,4 +1715,109 @@ BOOST_AUTO_TEST_CASE(test_LogEscapeMessage)
|
||||||
BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage(NUL), R"(O\x00O)");
|
BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage(NUL), R"(O\x00O)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct Tracker
|
||||||
|
{
|
||||||
|
//! Points to the original object (possibly itself) we moved/copied from
|
||||||
|
const Tracker* origin;
|
||||||
|
//! How many copies where involved between the original object and this one (moves are not counted)
|
||||||
|
int copies;
|
||||||
|
|
||||||
|
Tracker() noexcept : origin(this), copies(0) {}
|
||||||
|
Tracker(const Tracker& t) noexcept : origin(t.origin), copies(t.copies + 1) {}
|
||||||
|
Tracker(Tracker&& t) noexcept : origin(t.origin), copies(t.copies) {}
|
||||||
|
Tracker& operator=(const Tracker& t) noexcept
|
||||||
|
{
|
||||||
|
origin = t.origin;
|
||||||
|
copies = t.copies + 1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Tracker& operator=(Tracker&& t) noexcept
|
||||||
|
{
|
||||||
|
origin = t.origin;
|
||||||
|
copies = t.copies;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_tracked_vector)
|
||||||
|
{
|
||||||
|
Tracker t1;
|
||||||
|
Tracker t2;
|
||||||
|
Tracker t3;
|
||||||
|
|
||||||
|
BOOST_CHECK(t1.origin == &t1);
|
||||||
|
BOOST_CHECK(t2.origin == &t2);
|
||||||
|
BOOST_CHECK(t3.origin == &t3);
|
||||||
|
|
||||||
|
auto v1 = Vector(t1);
|
||||||
|
BOOST_CHECK_EQUAL(v1.size(), 1);
|
||||||
|
BOOST_CHECK(v1[0].origin == &t1);
|
||||||
|
BOOST_CHECK_EQUAL(v1[0].copies, 1);
|
||||||
|
|
||||||
|
auto v2 = Vector(std::move(t2));
|
||||||
|
BOOST_CHECK_EQUAL(v2.size(), 1);
|
||||||
|
BOOST_CHECK(v2[0].origin == &t2);
|
||||||
|
BOOST_CHECK_EQUAL(v2[0].copies, 0);
|
||||||
|
|
||||||
|
auto v3 = Vector(t1, std::move(t2));
|
||||||
|
BOOST_CHECK_EQUAL(v3.size(), 2);
|
||||||
|
BOOST_CHECK(v3[0].origin == &t1);
|
||||||
|
BOOST_CHECK(v3[1].origin == &t2);
|
||||||
|
BOOST_CHECK_EQUAL(v3[0].copies, 1);
|
||||||
|
BOOST_CHECK_EQUAL(v3[1].copies, 0);
|
||||||
|
|
||||||
|
auto v4 = Vector(std::move(v3[0]), v3[1], std::move(t3));
|
||||||
|
BOOST_CHECK_EQUAL(v4.size(), 3);
|
||||||
|
BOOST_CHECK(v4[0].origin == &t1);
|
||||||
|
BOOST_CHECK(v4[1].origin == &t2);
|
||||||
|
BOOST_CHECK(v4[2].origin == &t3);
|
||||||
|
BOOST_CHECK_EQUAL(v4[0].copies, 1);
|
||||||
|
BOOST_CHECK_EQUAL(v4[1].copies, 1);
|
||||||
|
BOOST_CHECK_EQUAL(v4[2].copies, 0);
|
||||||
|
|
||||||
|
auto v5 = Cat(v1, v4);
|
||||||
|
BOOST_CHECK_EQUAL(v5.size(), 4);
|
||||||
|
BOOST_CHECK(v5[0].origin == &t1);
|
||||||
|
BOOST_CHECK(v5[1].origin == &t1);
|
||||||
|
BOOST_CHECK(v5[2].origin == &t2);
|
||||||
|
BOOST_CHECK(v5[3].origin == &t3);
|
||||||
|
BOOST_CHECK_EQUAL(v5[0].copies, 2);
|
||||||
|
BOOST_CHECK_EQUAL(v5[1].copies, 2);
|
||||||
|
BOOST_CHECK_EQUAL(v5[2].copies, 2);
|
||||||
|
BOOST_CHECK_EQUAL(v5[3].copies, 1);
|
||||||
|
|
||||||
|
auto v6 = Cat(std::move(v1), v3);
|
||||||
|
BOOST_CHECK_EQUAL(v6.size(), 3);
|
||||||
|
BOOST_CHECK(v6[0].origin == &t1);
|
||||||
|
BOOST_CHECK(v6[1].origin == &t1);
|
||||||
|
BOOST_CHECK(v6[2].origin == &t2);
|
||||||
|
BOOST_CHECK_EQUAL(v6[0].copies, 1);
|
||||||
|
BOOST_CHECK_EQUAL(v6[1].copies, 2);
|
||||||
|
BOOST_CHECK_EQUAL(v6[2].copies, 1);
|
||||||
|
|
||||||
|
auto v7 = Cat(v2, std::move(v4));
|
||||||
|
BOOST_CHECK_EQUAL(v7.size(), 4);
|
||||||
|
BOOST_CHECK(v7[0].origin == &t2);
|
||||||
|
BOOST_CHECK(v7[1].origin == &t1);
|
||||||
|
BOOST_CHECK(v7[2].origin == &t2);
|
||||||
|
BOOST_CHECK(v7[3].origin == &t3);
|
||||||
|
BOOST_CHECK_EQUAL(v7[0].copies, 1);
|
||||||
|
BOOST_CHECK_EQUAL(v7[1].copies, 1);
|
||||||
|
BOOST_CHECK_EQUAL(v7[2].copies, 1);
|
||||||
|
BOOST_CHECK_EQUAL(v7[3].copies, 0);
|
||||||
|
|
||||||
|
auto v8 = Cat(std::move(v2), std::move(v3));
|
||||||
|
BOOST_CHECK_EQUAL(v8.size(), 3);
|
||||||
|
BOOST_CHECK(v8[0].origin == &t2);
|
||||||
|
BOOST_CHECK(v8[1].origin == &t1);
|
||||||
|
BOOST_CHECK(v8[2].origin == &t2);
|
||||||
|
BOOST_CHECK_EQUAL(v8[0].copies, 0);
|
||||||
|
BOOST_CHECK_EQUAL(v8[1].copies, 1);
|
||||||
|
BOOST_CHECK_EQUAL(v8[2].copies, 0);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
|
#include <util/vector.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -102,7 +103,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
|
||||||
// A vector is used for future extensibility, as we may want to support
|
// A vector is used for future extensibility, as we may want to support
|
||||||
// interrupting after partial writes from multiple independent reorgs.
|
// interrupting after partial writes from multiple independent reorgs.
|
||||||
batch.Erase(DB_BEST_BLOCK);
|
batch.Erase(DB_BEST_BLOCK);
|
||||||
batch.Write(DB_HEAD_BLOCKS, std::vector<uint256>{hashBlock, old_tip});
|
batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
|
||||||
|
|
||||||
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
|
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
|
||||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
|
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
|
||||||
|
|
51
src/util/vector.h
Normal file
51
src/util/vector.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright (c) 2019 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_UTIL_VECTOR_H
|
||||||
|
#define BITCOIN_UTIL_VECTOR_H
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/** Construct a vector with the specified elements.
|
||||||
|
*
|
||||||
|
* This is preferable over the list initializing constructor of std::vector:
|
||||||
|
* - It automatically infers the element type from its arguments.
|
||||||
|
* - If any arguments are rvalue references, they will be moved into the vector
|
||||||
|
* (list initialization always copies).
|
||||||
|
*/
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::vector<typename std::common_type<Args...>::type> Vector(Args&&... args)
|
||||||
|
{
|
||||||
|
std::vector<typename std::common_type<Args...>::type> ret;
|
||||||
|
ret.reserve(sizeof...(args));
|
||||||
|
// The line below uses the trick from https://www.experts-exchange.com/articles/32502/None-recursive-variadic-templates-with-std-initializer-list.html
|
||||||
|
(void)std::initializer_list<int>{(ret.emplace_back(std::forward<Args>(args)), 0)...};
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Concatenate two vectors, moving elements. */
|
||||||
|
template<typename V>
|
||||||
|
inline V Cat(V v1, V&& v2)
|
||||||
|
{
|
||||||
|
v1.reserve(v1.size() + v2.size());
|
||||||
|
for (auto& arg : v2) {
|
||||||
|
v1.push_back(std::move(arg));
|
||||||
|
}
|
||||||
|
return v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Concatenate two vectors. */
|
||||||
|
template<typename V>
|
||||||
|
inline V Cat(V v1, const V& v2)
|
||||||
|
{
|
||||||
|
v1.reserve(v1.size() + v2.size());
|
||||||
|
for (const auto& arg : v2) {
|
||||||
|
v1.push_back(arg);
|
||||||
|
}
|
||||||
|
return v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BITCOIN_UTIL_VECTOR_H
|
Loading…
Reference in a new issue