partial bitcoin#16889: Add some general std::vector utility functions

This commit is contained in:
Kittywhiskers Van Gogh 2019-10-10 11:23:41 -07:00
parent f2f1843f0c
commit 46151acdb5
5 changed files with 161 additions and 8 deletions

View File

@ -267,6 +267,7 @@ BITCOIN_CORE_H = \
util/string.h \
util/time.h \
util/threadnames.h \
util/vector.h \
validation.h \
validationinterface.h \
versionbits.h \

View File

@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bech32.h>
#include <util/vector.h>
namespace
{
@ -24,13 +25,6 @@ const int8_t CHARSET_REV[128] = {
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
* make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
* bits correspond to earlier values. */

View File

@ -11,6 +11,7 @@
#include <util/string.h>
#include <util/moneystr.h>
#include <test/test_dash.h>
#include <util/vector.h>
#include <stdint.h>
#include <vector>
@ -1162,4 +1163,109 @@ BOOST_AUTO_TEST_CASE(test_DirIsWritable)
fs::remove(tmpdirname);
}
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()

View File

@ -13,6 +13,7 @@
#include <util/system.h>
#include <ui_interface.h>
#include <init.h>
#include <util/vector.h>
#include <stdint.h>
@ -97,7 +98,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
// A vector is used for future extensibility, as we may want to support
// interrupting after partial writes from multiple independent reorgs.
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();) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) {

51
src/util/vector.h Normal file
View 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