diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp --- a/src/bench/prevector.cpp +++ b/src/bench/prevector.cpp @@ -1,15 +1,30 @@ -// Copyright (c) 2015-2017 The Bitcoin Core developers +// Copyright (c) 2015-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include #include +#include +#include +#include #include +// GCC 4.8 is missing some C++11 type_traits, +// https://www.gnu.org/software/gcc/gcc-5/changes.html +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 +#define IS_TRIVIALLY_CONSTRUCTIBLE std::has_trivial_default_constructor +#else +#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_default_constructible +#endif + struct nontrivial_t { int x; nontrivial_t() : x(-1) {} + ADD_SERIALIZE_METHODS + template + inline void SerializationOp(Stream &s, Operation ser_action) { + READWRITE(x); + } }; static_assert(!IS_TRIVIALLY_CONSTRUCTIBLE::value, "expected nontrivial_t to not be trivially constructible"); @@ -42,7 +57,7 @@ } } -template void PrevectorResize(benchmark::State &state) { +template static void PrevectorResize(benchmark::State &state) { while (state.KeepRunning()) { prevector<28, T> t0; prevector<28, T> t1; @@ -55,6 +70,27 @@ } } +template +static void PrevectorDeserialize(benchmark::State &state) { + CDataStream s0(SER_NETWORK, 0); + prevector<28, T> t0; + t0.resize(28); + for (auto x = 0; x < 900; ++x) { + s0 << t0; + } + t0.resize(100); + for (auto x = 0; x < 101; ++x) { + s0 << t0; + } + while (state.KeepRunning()) { + prevector<28, T> t1; + for (auto x = 0; x < 1000; ++x) { + s0 >> t1; + } + s0.Init(SER_NETWORK, 0); + } +} + #define PREVECTOR_TEST(name, nontrivops, trivops) \ static void Prevector##name##Nontrivial(benchmark::State &state) { \ Prevector##name(state); \ @@ -68,3 +104,4 @@ PREVECTOR_TEST(Clear, 28300, 88600) PREVECTOR_TEST(Destructor, 28800, 88900) PREVECTOR_TEST(Resize, 28900, 90300) +PREVECTOR_TEST(Deserialize, 6800, 52000) diff --git a/src/compat.h b/src/compat.h --- a/src/compat.h +++ b/src/compat.h @@ -10,16 +10,6 @@ #include #endif -#include - -// GCC 4.8 is missing some C++11 type_traits, -// https://www.gnu.org/software/gcc/gcc-5/changes.html -#if defined(__GNUC__) && __GNUC__ < 5 -#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivial -#else -#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_constructible -#endif - #ifdef WIN32 #ifdef _WIN32_WINNT #undef _WIN32_WINNT diff --git a/src/prevector.h b/src/prevector.h --- a/src/prevector.h +++ b/src/prevector.h @@ -5,17 +5,15 @@ #ifndef BITCOIN_PREVECTOR_H #define BITCOIN_PREVECTOR_H +#include #include +#include #include #include #include - -#include #include #include -#include - #pragma pack(push, 1) /** * Implements a drop-in replacement for std::vector which stores up to N @@ -234,14 +232,14 @@ }; private: - size_type _size; + size_type _size = 0; union direct_or_indirect { char direct[sizeof(T) * N]; struct { size_type capacity; char *indirect; }; - } _union; + } _union = {}; T *direct_ptr(difference_type pos) { return reinterpret_cast(_union.direct) + pos; @@ -299,23 +297,8 @@ return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } - void fill(T *dst, ptrdiff_t count) { - if (IS_TRIVIALLY_CONSTRUCTIBLE::value) { - // The most common use of prevector is where T=uint8_t. For - // trivially constructible types, we can use memset() to avoid - // looping. - ::memset(dst, 0, count * sizeof(T)); - } else { - for (auto i = 0; i < count; ++i) { - new (static_cast(dst + i)) T(); - } - } - } - - void fill(T *dst, ptrdiff_t count, const T &value) { - for (auto i = 0; i < count; ++i) { - new (static_cast(dst + i)) T(value); - } + void fill(T *dst, ptrdiff_t count, const T &value = T{}) { + std::fill_n(dst, count, value); } template @@ -348,34 +331,32 @@ fill(item_ptr(0), first, last); } - prevector() : _size(0), _union{{}} {} + prevector() {} - explicit prevector(size_type n) : prevector() { resize(n); } + explicit prevector(size_type n) { resize(n); } - explicit prevector(size_type n, const T &val) : prevector() { + explicit prevector(size_type n, const T &val) { change_capacity(n); _size += n; fill(item_ptr(0), n, val); } template - prevector(InputIterator first, InputIterator last) : prevector() { + prevector(InputIterator first, InputIterator last) { size_type n = last - first; change_capacity(n); _size += n; fill(item_ptr(0), first, last); } - prevector(const prevector &other) : prevector() { + prevector(const prevector &other) { size_type n = other.size(); change_capacity(n); _size += n; fill(item_ptr(0), other.begin(), other.end()); } - prevector(prevector &&other) : prevector() { - swap(other); - } + prevector(prevector &&other) { swap(other); } prevector &operator=(const prevector &other) { if (&other == this) {