Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2015-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#ifndef BITCOIN_PREVECTOR_H6#define BITCOIN_PREVECTOR_H8#include <algorithm>9#include <cassert>10#include <cstdint>11#include <cstdlib>12#include <cstring>13#include <iterator>14#include <new>15#include <type_traits>16#include <utility>18/** Implements a drop-in replacement for std::vector<T> which stores up to N19* elements directly (without heap allocation). The types Size and Diff are20* used to store element counts, and can be any unsigned + signed type.21*22* Storage layout is either:23* - Direct allocation:24* - Size _size: the number of used elements (between 0 and N)25* - T direct[N]: an array of N elements of type T26* (only the first _size are initialized).27* - Indirect allocation:28* - Size _size: the number of used elements plus N + 129* - Size capacity: the number of allocated elements30* - T* indirect: a pointer to an array of capacity elements of type T31* (only the first _size are initialized).32*33* The data type T must be movable by memmove/realloc(). Once we switch to C++,34* move constructors can be used instead.35*/36template<unsigned int N, typename T, typename Size = uint32_t, typename Diff = int32_t>37class prevector {38static_assert(std::is_trivially_copyable_v<T>);40public:41static constexpr unsigned int STATIC_SIZE{N};43typedef Size size_type;44typedef Diff difference_type;45typedef T value_type;46typedef value_type& reference;47typedef const value_type& const_reference;48typedef value_type* pointer;49typedef const value_type* const_pointer;51class iterator {52T* ptr{};53public:54typedef Diff difference_type;55typedef T* pointer;56typedef T& reference;57using element_type = T;58using iterator_category = std::contiguous_iterator_tag;59iterator() = default;60iterator(T* ptr_) : ptr(ptr_) {}61T& operator*() const { return *ptr; }62T* operator->() const { return ptr; }63T& operator[](size_type pos) const { return ptr[pos]; }64iterator& operator++() { ptr++; return *this; }65iterator& operator--() { ptr--; return *this; }66iterator operator++(int) { iterator copy(*this); ++(*this); return copy; }67iterator operator--(int) { iterator copy(*this); --(*this); return copy; }68difference_type friend operator-(iterator a, iterator b) { return (&(*a) - &(*b)); }69iterator operator+(size_type n) const { return iterator(ptr + n); }70iterator friend operator+(size_type n, iterator x) { return x + n; }71iterator& operator+=(size_type n) { ptr += n; return *this; }72iterator operator-(size_type n) const { return iterator(ptr - n); }73iterator& operator-=(size_type n) { ptr -= n; return *this; }74bool operator==(iterator x) const { return ptr == x.ptr; }75auto operator<=>(iterator x) const { return ptr <=> x.ptr; }76};78class const_iterator {79const T* ptr{};80public:81typedef Diff difference_type;82typedef const T* pointer;83typedef const T& reference;84using element_type = const T;85using iterator_category = std::contiguous_iterator_tag;86const_iterator() = default;87const_iterator(const T* ptr_) : ptr(ptr_) {}88const_iterator(iterator x) : ptr(&(*x)) {}89const T& operator*() const { return *ptr; }90const T* operator->() const { return ptr; }91const T& operator[](size_type pos) const { return ptr[pos]; }92const_iterator& operator++() { ptr++; return *this; }93const_iterator& operator--() { ptr--; return *this; }94const_iterator operator++(int) { const_iterator copy(*this); ++(*this); return copy; }95const_iterator operator--(int) { const_iterator copy(*this); --(*this); return copy; }96difference_type friend operator-(const_iterator a, const_iterator b) { return (&(*a) - &(*b)); }97const_iterator operator+(size_type n) const { return const_iterator(ptr + n); }98const_iterator friend operator+(size_type n, const_iterator x) { return x + n; }99const_iterator& operator+=(size_type n) { ptr += n; return *this; }100const_iterator operator-(size_type n) const { return const_iterator(ptr - n); }101const_iterator& operator-=(size_type n) { ptr -= n; return *this; }102bool operator==(const_iterator x) const { return ptr == x.ptr; }103auto operator<=>(const_iterator x) const { return ptr <=> x.ptr; }104};106private:107#pragma pack(push, 1)108union direct_or_indirect {109char direct[sizeof(T) * N];110struct {111char* indirect;112size_type capacity;113} indirect_contents;114};115#pragma pack(pop)116alignas(char*) direct_or_indirect _union = {};117size_type _size = 0;119static_assert(alignof(char*) % alignof(size_type) == 0 && sizeof(char*) % alignof(size_type) == 0, "size_type cannot have more restrictive alignment requirement than pointer");120static_assert(alignof(char*) % alignof(T) == 0, "value_type T cannot have more restrictive alignment requirement than pointer");122T* direct_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.direct) + pos; }123const T* direct_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.direct) + pos; }124T* indirect_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.indirect_contents.indirect) + pos; }125const T* indirect_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.indirect_contents.indirect) + pos; }126bool is_direct() const { return _size <= N; }128void change_capacity(size_type new_capacity) {129if (new_capacity <= N) {130if (!is_direct()) {131T* indirect = indirect_ptr(0);132T* src = indirect;133T* dst = direct_ptr(0);134memcpy(dst, src, size() * sizeof(T));135free(indirect);136_size -= N + 1;137}138} else {139if (!is_direct()) {140/* FIXME: Because malloc/realloc here won't call new_handler if allocation fails, assert141success. These should instead use an allocator or new/delete so that handlers142are called as necessary, but performance would be slightly degraded by doing so. */143_union.indirect_contents.indirect = static_cast<char*>(realloc(_union.indirect_contents.indirect, ((size_t)sizeof(T)) * new_capacity));144assert(_union.indirect_contents.indirect);145_union.indirect_contents.capacity = new_capacity;146} else {147char* new_indirect = static_cast<char*>(malloc(((size_t)sizeof(T)) * new_capacity));148assert(new_indirect);149T* src = direct_ptr(0);150T* dst = reinterpret_cast<T*>(new_indirect);151memcpy(dst, src, size() * sizeof(T));152_union.indirect_contents.indirect = new_indirect;153_union.indirect_contents.capacity = new_capacity;154_size += N + 1;155}156}157}159T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }160const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }162void fill(T* dst, ptrdiff_t count, const T& value = T{}) {163std::fill_n(dst, count, value);164}166template <std::input_iterator InputIterator>167void fill(T* dst, InputIterator first, InputIterator last) {168while (first != last) {169new(static_cast<void*>(dst)) T(*first);170++dst;171++first;172}173}175public:176void assign(size_type n, const T& val) {177clear();178if (capacity() < n) {179change_capacity(n);180}181_size += n;182fill(item_ptr(0), n, val);183}185template <std::input_iterator InputIterator>186void assign(InputIterator first, InputIterator last) {187size_type n = last - first;188clear();189if (capacity() < n) {190change_capacity(n);191}192_size += n;193fill(item_ptr(0), first, last);194}196prevector() = default;198explicit prevector(size_type n) {199resize(n);200}202explicit prevector(size_type n, const T& val) {203change_capacity(n);204_size += n;205fill(item_ptr(0), n, val);206}208template <std::input_iterator InputIterator>209prevector(InputIterator first, InputIterator last) {210size_type n = last - first;211change_capacity(n);212_size += n;213fill(item_ptr(0), first, last);214}216prevector(const prevector<N, T, Size, Diff>& other) {217size_type n = other.size();218change_capacity(n);219_size += n;220fill(item_ptr(0), other.begin(), other.end());221}223prevector(prevector<N, T, Size, Diff>&& other) noexcept224: _union(std::move(other._union)), _size(other._size)225{226other._size = 0;227}229prevector& operator=(const prevector<N, T, Size, Diff>& other) {230if (&other == this) {231return *this;232}233assign(other.begin(), other.end());234return *this;235}237prevector& operator=(prevector<N, T, Size, Diff>&& other) noexcept {238if (!is_direct()) {239free(_union.indirect_contents.indirect);240}241_union = std::move(other._union);242_size = other._size;243other._size = 0;244return *this;245}247size_type size() const {248return is_direct() ? _size : _size - N - 1;249}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.