@ -1,17 +1,20 @@
// Copyright (c) 2016-2021 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_
// Copyright (c) 2015-2020 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_PREVECTOR_H
# define BITCOIN_PREVECTOR_H
# include <util.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 +133,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 +146,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 +182,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 +201,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 +231,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 +301,7 @@ public:
if ( is_direct ( ) ) {
return N ;
} else {
return _union . capacity ;
return _union . indirect_contents . capacity ;
}
}
@ -303,17 +314,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 +350,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 +363,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 +377,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 +459,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 +521,17 @@ public:
if ( is_direct ( ) ) {
return 0 ;
} else {
return ( ( size_t ) ( sizeof ( T ) ) ) * _union . capacity ;
return ( ( size_t ) ( sizeof ( T ) ) ) * _union . indirect_contents . capacity ;
}
}
value_type * data ( ) {
return item_ptr ( 0 ) ;
}
const value_type * data ( ) const {
return item_ptr ( 0 ) ;
}
} ;
# pragma pack(pop)
# endif
# endif // BITCOIN_PREVECTOR_H