BIP155 (addrv2)
Tor v3 + i2p
This commit is contained in:
245
src/prevector.h
245
src/prevector.h
@@ -1,17 +1,21 @@
|
||||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2022 The Hush developers
|
||||
// Distributed under the GPLv3 software license, see the accompanying
|
||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
#ifndef _HUSH_PREVECTOR_H_
|
||||
#define _HUSH_PREVECTOR_H_
|
||||
|
||||
#include <util.h>
|
||||
#ifndef HUSH_PREVECTOR_H
|
||||
#define HUSH_PREVECTOR_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <iterator>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
/** Implements a drop-in replacement for std::vector<T> which stores up to N
|
||||
* elements directly (without heap allocation). The types Size and Diff are
|
||||
* used to store element counts, and can be any unsigned + signed type.
|
||||
@@ -130,7 +134,7 @@ public:
|
||||
typedef const T* pointer;
|
||||
typedef const T& reference;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
const_reverse_iterator(T* ptr_) : ptr(ptr_) {}
|
||||
const_reverse_iterator(const T* ptr_) : ptr(ptr_) {}
|
||||
const_reverse_iterator(reverse_iterator x) : ptr(&(*x)) {}
|
||||
const T& operator*() const { return *ptr; }
|
||||
const T* operator->() const { return ptr; }
|
||||
@@ -143,19 +147,25 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
size_type _size;
|
||||
union {
|
||||
#pragma pack(push, 1)
|
||||
union direct_or_indirect {
|
||||
char direct[sizeof(T) * N];
|
||||
struct {
|
||||
size_type capacity;
|
||||
char* indirect;
|
||||
};
|
||||
} _union;
|
||||
size_type capacity;
|
||||
} indirect_contents;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
alignas(char*) direct_or_indirect _union = {};
|
||||
size_type _size = 0;
|
||||
|
||||
static_assert(alignof(char*) % alignof(size_type) == 0 && sizeof(char*) % alignof(size_type) == 0, "size_type cannot have more restrictive alignment requirement than pointer");
|
||||
static_assert(alignof(char*) % alignof(T) == 0, "value_type T cannot have more restrictive alignment requirement than pointer");
|
||||
|
||||
T* direct_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.direct) + pos; }
|
||||
const T* direct_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.direct) + pos; }
|
||||
T* indirect_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.indirect) + pos; }
|
||||
const T* indirect_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.indirect) + pos; }
|
||||
T* indirect_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.indirect_contents.indirect) + pos; }
|
||||
const T* indirect_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.indirect_contents.indirect) + pos; }
|
||||
bool is_direct() const { return _size <= N; }
|
||||
|
||||
void change_capacity(size_type new_capacity) {
|
||||
@@ -173,17 +183,17 @@ private:
|
||||
/* FIXME: Because malloc/realloc here won't call new_handler if allocation fails, assert
|
||||
success. These should instead use an allocator or new/delete so that handlers
|
||||
are called as necessary, but performance would be slightly degraded by doing so. */
|
||||
_union.indirect = static_cast<char*>(realloc(_union.indirect, ((size_t)sizeof(T)) * new_capacity));
|
||||
if (!_union.indirect) { new_handler_terminate(); }
|
||||
_union.capacity = new_capacity;
|
||||
_union.indirect_contents.indirect = static_cast<char*>(realloc(_union.indirect_contents.indirect, ((size_t)sizeof(T)) * new_capacity));
|
||||
assert(_union.indirect_contents.indirect);
|
||||
_union.indirect_contents.capacity = new_capacity;
|
||||
} else {
|
||||
char* new_indirect = static_cast<char*>(malloc(((size_t)sizeof(T)) * new_capacity));
|
||||
if (!new_indirect) { new_handler_terminate(); }
|
||||
assert(new_indirect);
|
||||
T* src = direct_ptr(0);
|
||||
T* dst = reinterpret_cast<T*>(new_indirect);
|
||||
memcpy(dst, src, size() * sizeof(T));
|
||||
_union.indirect = new_indirect;
|
||||
_union.capacity = new_capacity;
|
||||
_union.indirect_contents.indirect = new_indirect;
|
||||
_union.indirect_contents.capacity = new_capacity;
|
||||
_size += N + 1;
|
||||
}
|
||||
}
|
||||
@@ -192,16 +202,27 @@ private:
|
||||
T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }
|
||||
const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }
|
||||
|
||||
void fill(T* dst, ptrdiff_t count, const T& value = T{}) {
|
||||
std::fill_n(dst, count, value);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
void fill(T* dst, InputIterator first, InputIterator last) {
|
||||
while (first != last) {
|
||||
new(static_cast<void*>(dst)) T(*first);
|
||||
++dst;
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void assign(size_type n, const T& val) {
|
||||
clear();
|
||||
if (capacity() < n) {
|
||||
change_capacity(n);
|
||||
}
|
||||
while (size() < n) {
|
||||
_size++;
|
||||
new(static_cast<void*>(item_ptr(size() - 1))) T(val);
|
||||
}
|
||||
_size += n;
|
||||
fill(item_ptr(0), n, val);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
@@ -211,60 +232,51 @@ public:
|
||||
if (capacity() < n) {
|
||||
change_capacity(n);
|
||||
}
|
||||
while (first != last) {
|
||||
_size++;
|
||||
new(static_cast<void*>(item_ptr(size() - 1))) T(*first);
|
||||
++first;
|
||||
}
|
||||
_size += n;
|
||||
fill(item_ptr(0), first, last);
|
||||
}
|
||||
|
||||
prevector() : _size(0) {}
|
||||
prevector() {}
|
||||
|
||||
explicit prevector(size_type n) : _size(0) {
|
||||
explicit prevector(size_type n) {
|
||||
resize(n);
|
||||
}
|
||||
|
||||
explicit prevector(size_type n, const T& val = T()) : _size(0) {
|
||||
explicit prevector(size_type n, const T& val) {
|
||||
change_capacity(n);
|
||||
while (size() < n) {
|
||||
_size++;
|
||||
new(static_cast<void*>(item_ptr(size() - 1))) T(val);
|
||||
}
|
||||
_size += n;
|
||||
fill(item_ptr(0), n, val);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
prevector(InputIterator first, InputIterator last) : _size(0) {
|
||||
prevector(InputIterator first, InputIterator last) {
|
||||
size_type n = last - first;
|
||||
change_capacity(n);
|
||||
while (first != last) {
|
||||
_size++;
|
||||
new(static_cast<void*>(item_ptr(size() - 1))) T(*first);
|
||||
++first;
|
||||
}
|
||||
_size += n;
|
||||
fill(item_ptr(0), first, last);
|
||||
}
|
||||
|
||||
prevector(const prevector<N, T, Size, Diff>& other) : _size(0) {
|
||||
change_capacity(other.size());
|
||||
const_iterator it = other.begin();
|
||||
while (it != other.end()) {
|
||||
_size++;
|
||||
new(static_cast<void*>(item_ptr(size() - 1))) T(*it);
|
||||
++it;
|
||||
}
|
||||
prevector(const prevector<N, T, Size, Diff>& other) {
|
||||
size_type n = other.size();
|
||||
change_capacity(n);
|
||||
_size += n;
|
||||
fill(item_ptr(0), other.begin(), other.end());
|
||||
}
|
||||
|
||||
prevector(prevector<N, T, Size, Diff>&& other) {
|
||||
swap(other);
|
||||
}
|
||||
|
||||
prevector& operator=(const prevector<N, T, Size, Diff>& other) {
|
||||
if (&other == this) {
|
||||
return *this;
|
||||
}
|
||||
resize(0);
|
||||
change_capacity(other.size());
|
||||
const_iterator it = other.begin();
|
||||
while (it != other.end()) {
|
||||
_size++;
|
||||
new(static_cast<void*>(item_ptr(size() - 1))) T(*it);
|
||||
++it;
|
||||
}
|
||||
assign(other.begin(), other.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
prevector& operator=(prevector<N, T, Size, Diff>&& other) {
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -290,7 +302,7 @@ public:
|
||||
if (is_direct()) {
|
||||
return N;
|
||||
} else {
|
||||
return _union.capacity;
|
||||
return _union.indirect_contents.capacity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,17 +315,20 @@ public:
|
||||
}
|
||||
|
||||
void resize(size_type new_size) {
|
||||
while (size() > new_size) {
|
||||
item_ptr(size() - 1)->~T();
|
||||
_size--;
|
||||
size_type cur_size = size();
|
||||
if (cur_size == new_size) {
|
||||
return;
|
||||
}
|
||||
if (cur_size > new_size) {
|
||||
erase(item_ptr(new_size), end());
|
||||
return;
|
||||
}
|
||||
if (new_size > capacity()) {
|
||||
change_capacity(new_size);
|
||||
}
|
||||
while (size() < new_size) {
|
||||
_size++;
|
||||
new(static_cast<void*>(item_ptr(size() - 1))) T();
|
||||
}
|
||||
ptrdiff_t increase = new_size - cur_size;
|
||||
fill(item_ptr(cur_size), increase);
|
||||
_size += increase;
|
||||
}
|
||||
|
||||
void reserve(size_type new_capacity) {
|
||||
@@ -336,10 +351,11 @@ public:
|
||||
if (capacity() < new_size) {
|
||||
change_capacity(new_size + (new_size >> 1));
|
||||
}
|
||||
memmove(item_ptr(p + 1), item_ptr(p), (size() - p) * sizeof(T));
|
||||
T* ptr = item_ptr(p);
|
||||
memmove(ptr + 1, ptr, (size() - p) * sizeof(T));
|
||||
_size++;
|
||||
new(static_cast<void*>(item_ptr(p))) T(value);
|
||||
return iterator(item_ptr(p));
|
||||
new(static_cast<void*>(ptr)) T(value);
|
||||
return iterator(ptr);
|
||||
}
|
||||
|
||||
void insert(iterator pos, size_type count, const T& value) {
|
||||
@@ -348,11 +364,10 @@ public:
|
||||
if (capacity() < new_size) {
|
||||
change_capacity(new_size + (new_size >> 1));
|
||||
}
|
||||
memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T));
|
||||
T* ptr = item_ptr(p);
|
||||
memmove(ptr + count, ptr, (size() - p) * sizeof(T));
|
||||
_size += count;
|
||||
for (size_type i = 0; i < count; i++) {
|
||||
new(static_cast<void*>(item_ptr(p + i))) T(value);
|
||||
}
|
||||
fill(item_ptr(p), count, value);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
@@ -363,45 +378,69 @@ public:
|
||||
if (capacity() < new_size) {
|
||||
change_capacity(new_size + (new_size >> 1));
|
||||
}
|
||||
memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T));
|
||||
T* ptr = item_ptr(p);
|
||||
memmove(ptr + count, ptr, (size() - p) * sizeof(T));
|
||||
_size += count;
|
||||
while (first != last) {
|
||||
new(static_cast<void*>(item_ptr(p))) T(*first);
|
||||
++p;
|
||||
++first;
|
||||
fill(ptr, first, last);
|
||||
}
|
||||
|
||||
inline void resize_uninitialized(size_type new_size) {
|
||||
// resize_uninitialized changes the size of the prevector but does not initialize it.
|
||||
// If size < new_size, the added elements must be initialized explicitly.
|
||||
if (capacity() < new_size) {
|
||||
change_capacity(new_size);
|
||||
_size += new_size - size();
|
||||
return;
|
||||
}
|
||||
if (new_size < size()) {
|
||||
erase(item_ptr(new_size), end());
|
||||
} else {
|
||||
_size += new_size - size();
|
||||
}
|
||||
}
|
||||
|
||||
iterator erase(iterator pos) {
|
||||
(*pos).~T();
|
||||
memmove(&(*pos), &(*pos) + 1, ((char*)&(*end())) - ((char*)(1 + &(*pos))));
|
||||
_size--;
|
||||
return pos;
|
||||
return erase(pos, pos + 1);
|
||||
}
|
||||
|
||||
iterator erase(iterator first, iterator last) {
|
||||
// Erase is not allowed to the change the object's capacity. That means
|
||||
// that when starting with an indirectly allocated prevector with
|
||||
// size and capacity > N, the result may be a still indirectly allocated
|
||||
// prevector with size <= N and capacity > N. A shrink_to_fit() call is
|
||||
// necessary to switch to the (more efficient) directly allocated
|
||||
// representation (with capacity N and size <= N).
|
||||
iterator p = first;
|
||||
char* endp = (char*)&(*end());
|
||||
while (p != last) {
|
||||
(*p).~T();
|
||||
_size--;
|
||||
++p;
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
while (p != last) {
|
||||
(*p).~T();
|
||||
_size--;
|
||||
++p;
|
||||
}
|
||||
} else {
|
||||
_size -= last - p;
|
||||
}
|
||||
memmove(&(*first), &(*last), endp - ((char*)(&(*last))));
|
||||
return first;
|
||||
}
|
||||
|
||||
void push_back(const T& value) {
|
||||
template<typename... Args>
|
||||
void emplace_back(Args&&... args) {
|
||||
size_type new_size = size() + 1;
|
||||
if (capacity() < new_size) {
|
||||
change_capacity(new_size + (new_size >> 1));
|
||||
}
|
||||
new(item_ptr(size())) T(value);
|
||||
new(item_ptr(size())) T(std::forward<Args>(args)...);
|
||||
_size++;
|
||||
}
|
||||
|
||||
void push_back(const T& value) {
|
||||
emplace_back(value);
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
_size--;
|
||||
erase(end() - 1, end());
|
||||
}
|
||||
|
||||
T& front() {
|
||||
@@ -421,20 +460,17 @@ public:
|
||||
}
|
||||
|
||||
void swap(prevector<N, T, Size, Diff>& other) {
|
||||
if (_size & other._size & 1) {
|
||||
std::swap(_union.capacity, other._union.capacity);
|
||||
std::swap(_union.indirect, other._union.indirect);
|
||||
} else {
|
||||
std::swap(_union, other._union);
|
||||
}
|
||||
std::swap(_union, other._union);
|
||||
std::swap(_size, other._size);
|
||||
}
|
||||
|
||||
~prevector() {
|
||||
clear();
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
clear();
|
||||
}
|
||||
if (!is_direct()) {
|
||||
free(_union.indirect);
|
||||
_union.indirect = NULL;
|
||||
free(_union.indirect_contents.indirect);
|
||||
_union.indirect_contents.indirect = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,10 +522,17 @@ public:
|
||||
if (is_direct()) {
|
||||
return 0;
|
||||
} else {
|
||||
return ((size_t)(sizeof(T))) * _union.capacity;
|
||||
return ((size_t)(sizeof(T))) * _union.indirect_contents.capacity;
|
||||
}
|
||||
}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
value_type* data() {
|
||||
return item_ptr(0);
|
||||
}
|
||||
|
||||
const value_type* data() const {
|
||||
return item_ptr(0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // HUSH_PREVECTOR_H
|
||||
|
||||
Reference in New Issue
Block a user