Skip to content

Commit

Permalink
variant_vector (#18)
Browse files Browse the repository at this point in the history
* cleanups

* first kinda working variant_vector impl

* iterator conversion spaghetti

* small fixes and cleanups in variant_vector

* fix up var_vector, other cleanups
  • Loading branch information
eddieavd authored Nov 6, 2024
1 parent 245acc8 commit 62f95b2
Show file tree
Hide file tree
Showing 8 changed files with 884 additions and 28 deletions.
31 changes: 23 additions & 8 deletions bench/gbench_uti.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <allocator/freelist_resource.hpp>
#include <container/vector.hpp>
#include <container/variant_vector.hpp>

#include <vector>
#include <string>
Expand All @@ -22,18 +23,31 @@ using stdvecstr = std::vector< std::string > ;
using utivecint = uti::vector< int, uti::allocator< int, uti::malloc_resource > > ;
using utivecstr = uti::vector< std::string, uti::allocator< std::string, uti::malloc_resource > > ;

using utivecintstat = uti::vector< int, uti::allocator< int, uti::static_bump_resource< 16 * 1024 * 1024 > > > ;
using utivecstrstat = uti::vector< std::string, uti::allocator< std::string, uti::static_bump_resource< 16 * 1024 * 1024 > > > ;
using utivarvec = uti::variant_vector< uti::malloc_resource, int > ;

using utivecintlist = uti::vector< int, uti::allocator< int, uti::static_freelist_resource< 16 * 1024 * 1024 > > > ;
using utivecstrlist = uti::vector< std::string, uti::allocator< std::string, uti::static_freelist_resource< 16 * 1024 * 1024 > > > ;
using utivecintstat = uti::vector< int, uti::allocator< int, uti::static_bump_resource< 16 * 1024 * 1024, 1 > > > ;
using utivecstrstat = uti::vector< std::string, uti::allocator< std::string, uti::static_bump_resource< 16 * 1024 * 1024, 2 > > > ;

using utivarvecstat = uti::variant_vector< uti::static_bump_resource< 32 * 1024 * 1024, 3 >, int > ;

BENCHMARK( bm_push_back_trivial< stdvecint > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_trivial< utivecint > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_trivial< utivecintstat > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_trivial< utivecintlist > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
using utivecintlist = uti::vector< int, uti::allocator< int, uti::static_freelist_resource< 16 * 1024 * 1024, 4 > > > ;
using utivecstrlist = uti::vector< std::string, uti::allocator< std::string, uti::static_freelist_resource< 16 * 1024 * 1024, 5 > > > ;

using utivarveclist = uti::variant_vector< uti::static_freelist_resource< 32 * 1024 * 1024, 6 >, int > ;


BENCHMARK( bm_sum_vector < stdvecint > )->RangeMultiplier( 4 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond ) ;
BENCHMARK( bm_sum_vector < utivecint > )->RangeMultiplier( 4 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond ) ;
BENCHMARK( bm_sum_vector < utivecintstat > )->RangeMultiplier( 4 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond ) ;
BENCHMARK( bm_sum_var_vector< utivarvec > )->RangeMultiplier( 4 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond ) ;

BENCHMARK( bm_push_back_trivial< stdvecint > )->RangeMultiplier( 4 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_trivial< utivecint > )->RangeMultiplier( 4 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_trivial< utivecintstat > )->RangeMultiplier( 4 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_trivial< utivecintlist > )->RangeMultiplier( 4 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_trivial< utivarvec > )->RangeMultiplier( 4 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );

/*
BENCHMARK( bm_push_back_nontrivial< stdvecstr > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_nontrivial< utivecstr > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_nontrivial< utivecstrstat > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
Expand All @@ -48,6 +62,7 @@ BENCHMARK( bm_push_back_reserved_nontrivial< stdvecstr > )->RangeMultiplier(
BENCHMARK( bm_push_back_reserved_nontrivial< utivecstr > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_reserved_nontrivial< utivecstrstat > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
BENCHMARK( bm_push_back_reserved_nontrivial< utivecstrlist > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
*/

/*
BENCHMARK( bm_copy_container_trivial< stdvecint > )->RangeMultiplier( 2 )->Range( 1024, 1024 << 10 )->Unit( benchmark::kMicrosecond );
Expand Down
68 changes: 68 additions & 0 deletions bench/gbench_uti.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,57 @@ namespace uti::bench
{


template< typename T >
static void bm_sum_vector ( benchmark::State & state )
{
srand( time( nullptr ) ) ;

T vector ;

for( int i = 0; i < state.range( 0 ); ++i )
{
vector.push_back( rand() % 1024 ) ;
}
long long sum = 0 ;

for( auto _ : state )
{
for( long i = 0; i < ( long )vector.size(); ++i )
{
sum += vector.at( i ) ;
}
benchmark::ClobberMemory() ;
benchmark::DoNotOptimize( sum ) ;
benchmark::DoNotOptimize( vector ) ;
}
}

template< typename T >
static void bm_sum_var_vector ( benchmark::State & state )
{
srand( time( nullptr ) ) ;

T vector ;

for( int i = 0; i < state.range( 0 ); ++i )
{
vector.template push_back< int >( rand() % 1024 ) ;
}
long long sum = 0 ;

for( auto _ : state )
{
for( long i = 0; i < vector.size(); ++i )
{
vector.visit( i, [ & ]( int const & val ){ sum += val ; } ) ;
}
benchmark::ClobberMemory() ;
benchmark::DoNotOptimize( sum ) ;
benchmark::DoNotOptimize( vector ) ;
}
}


template< typename T >
static void bm_push_back_trivial ( benchmark::State & state )
{
Expand Down Expand Up @@ -62,6 +113,23 @@ static void bm_push_back_reserved_trivial ( benchmark::State & state )
}
}

template< typename T >
static void bm_push_back_var_reserved_trivial ( benchmark::State & state )
{
for( auto _ : state )
{
T container;
container.template reserve< int >( state.range( 0 ) );

for( ssize_t i = 0; i < state.range( 0 ); ++i )
{
container.template push_back< int >( 1024 );
}
benchmark::ClobberMemory();
benchmark::DoNotOptimize( container );
}
}

template< typename T >
static void bm_push_back_reserved_nontrivial ( benchmark::State & state )
{
Expand Down
58 changes: 58 additions & 0 deletions test/gtest_iterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,61 @@ TEST( IteratorTest, ContainerIterators )
static_assert( uti::meta::random_access_iterator< r_segtree_iter > ) ;
static_assert( uti::meta::random_access_iterator< c_r_segtree_iter > ) ;
}

TEST( IteratorTest, Convertibility )
{
using iter_u8 = uti::iterator_base< uti:: u8_t, uti::random_access_iterator_tag > ;
using iter_u64 = uti::iterator_base< uti:: u64_t, uti::random_access_iterator_tag > ;
using iter_str = uti::iterator_base< uti::string, uti::random_access_iterator_tag > ;

using const_iter_u8 = uti::iterator_base< uti:: u8_t const, uti::random_access_iterator_tag > ;
using const_iter_u64 = uti::iterator_base< uti:: u64_t const, uti::random_access_iterator_tag > ;
using const_iter_str = uti::iterator_base< uti::string const, uti::random_access_iterator_tag > ;

/// self
{
static_assert( uti::is_convertible_v< iter_u8, iter_u8 > ) ;
static_assert( uti::is_convertible_v< iter_u8, const_iter_u8 > ) ;
static_assert( !uti::is_convertible_v< const_iter_u8, iter_u8 > ) ;
static_assert( uti::is_convertible_v< const_iter_u8, const_iter_u8 > ) ;

static_assert( uti::is_convertible_v< iter_u64, iter_u64 > ) ;
static_assert( uti::is_convertible_v< iter_u64, const_iter_u64 > ) ;
static_assert( !uti::is_convertible_v< const_iter_u64, iter_u64 > ) ;
static_assert( uti::is_convertible_v< const_iter_u64, const_iter_u64 > ) ;

static_assert( uti::is_convertible_v< iter_u64, iter_u64 > ) ;
static_assert( uti::is_convertible_v< iter_u64, const_iter_u64 > ) ;
static_assert( !uti::is_convertible_v< const_iter_u64, iter_u64 > ) ;
static_assert( uti::is_convertible_v< const_iter_u64, const_iter_u64 > ) ;
}
/// to and from u8
{
static_assert( uti::is_convertible_v< iter_u64, iter_u8 > ) ;
static_assert( uti::is_convertible_v< iter_u64, const_iter_u8 > ) ;
static_assert( !uti::is_convertible_v< const_iter_u64, iter_u8 > ) ;
static_assert( uti::is_convertible_v< const_iter_u64, const_iter_u8 > ) ;

static_assert( uti::is_convertible_v< iter_u8, iter_u64 > ) ;
static_assert( uti::is_convertible_v< iter_u8, const_iter_u64 > ) ;
static_assert( !uti::is_convertible_v< const_iter_u8, iter_u64 > ) ;
static_assert( uti::is_convertible_v< const_iter_u8, const_iter_u64 > ) ;

static_assert( uti::is_convertible_v< iter_str, iter_u8 > ) ;
static_assert( uti::is_convertible_v< iter_str, const_iter_u8 > ) ;
static_assert( !uti::is_convertible_v< const_iter_str, iter_u8 > ) ;
static_assert( uti::is_convertible_v< const_iter_str, const_iter_u8 > ) ;

static_assert( uti::is_convertible_v< iter_u8, iter_str > ) ;
static_assert( uti::is_convertible_v< iter_u8, const_iter_str > ) ;
static_assert( !uti::is_convertible_v< const_iter_u8, iter_str > ) ;
static_assert( uti::is_convertible_v< const_iter_u8, const_iter_str > ) ;
}
/// between different types
{
static_assert( !uti::is_convertible_v< iter_u64, iter_str > ) ;
static_assert( !uti::is_convertible_v< iter_u64, const_iter_str > ) ;
static_assert( !uti::is_convertible_v< const_iter_u64, iter_str > ) ;
static_assert( !uti::is_convertible_v< const_iter_u64, const_iter_str > ) ;
}
}
8 changes: 7 additions & 1 deletion uti/allocator/freelist_resource.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <container/list.hpp>

#ifndef UTI_FREELIST_CAP
#define UTI_FREELIST_CAP 32
#define UTI_FREELIST_CAP 64
#endif // UTI_FREELIST_CAP

#ifndef UTI_FREELIST_TAG
Expand Down Expand Up @@ -198,6 +198,12 @@ struct static_freelist_resource
_block_. size_ = 0 ;
}

static constexpr void reset () noexcept
{
freelist_.clear() ;
freelist_.push_back( block_type{ mem_.mem_, memsize } ) ;
}

UTI_NODISCARD static constexpr ssize_type capacity () noexcept { return memsize ; }

UTI_NODISCARD static constexpr iterator begin () noexcept { return mem_.mem_ ; }
Expand Down
13 changes: 12 additions & 1 deletion uti/allocator/resource.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct resource_traits
return resource_type::realloc_inplace( _block_, _bytes_ ) ;
}
UTI_NODISCARD UTI_DEEP_INLINE static constexpr
bool realloc_inplace ( block_type &, ssize_type, ssize_type const ) noexcept
bool realloc_inplace ( block_type &, ssize_type ) noexcept
requires( !is_detected_v< has_inplace_realloc, resource_type, value_type > )
{
return false ;
Expand All @@ -82,6 +82,11 @@ struct resource_traits
{
return i64_t_max ;
}
UTI_DEEP_INLINE static constexpr
void reset () noexcept
{
resource_type::reset() ;
}
} ;


Expand Down Expand Up @@ -132,6 +137,7 @@ struct malloc_resource
_block_.begin_ = nullptr ;
_block_. size_ = 0 ;
}
static constexpr void reset () noexcept {}
} ;


Expand Down Expand Up @@ -206,6 +212,11 @@ struct static_bump_resource
_block_. size_ = 0 ;
}

static constexpr void reset () noexcept
{
end_ = mem_.mem_ ;
}

UTI_NODISCARD static constexpr ssize_type capacity () noexcept { return memsize ; }

UTI_NODISCARD static constexpr iterator begin () noexcept { return mem_.mem_ ; }
Expand Down
84 changes: 82 additions & 2 deletions uti/container/list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,9 @@ class list
using const_reference = value_type const & ;

using node_pointer = node_type * ;
using node_const_pointer = node_type const * ;
using const_node_pointer = node_type const * ;
using node_reference = node_type & ;
using node_const_reference = node_type const & ;
using const_node_reference = node_type const & ;

using iterator = list_iterator< node_type > ;
using const_iterator = list_iterator< node_type const > ;
Expand All @@ -194,6 +194,11 @@ class list
constexpr list ( std::initializer_list< value_type > _list_ ) UTI_NOEXCEPT_UNLESS_BADALLOC ;
#endif // UTI_HAS_STL

constexpr list ( list const & ) UTI_NOEXCEPT_UNLESS_BADALLOC ;
constexpr list ( list && ) noexcept ;
constexpr list & operator= ( list const & ) UTI_NOEXCEPT_UNLESS_BADALLOC ;
constexpr list & operator= ( list && ) noexcept ;

constexpr ~list () noexcept { clear() ; }

constexpr void push_back ( value_type const & _val_ ) UTI_NOEXCEPT_UNLESS_BADALLOC ;
Expand All @@ -214,6 +219,14 @@ class list
requires meta::constructible_from< value_type, Args... >
constexpr void insert ( iterator _position_, Args&&... _args_ ) UTI_NOEXCEPT_UNLESS_BADALLOC ;

template< meta::forward_iterator Iter >
requires meta::convertible_to< iter_value_t< Iter >, value_type >
constexpr void append ( Iter _begin_, Iter const _end_ ) UTI_NOEXCEPT_UNLESS_BADALLOC ;

template< meta::simple_container Other >
requires meta::convertible_to< typename Other::value_type, value_type >
constexpr void append ( Other const & _other_ ) UTI_NOEXCEPT_UNLESS_BADALLOC ;

constexpr void pop_back () noexcept ;
constexpr void pop_front () noexcept ;

Expand Down Expand Up @@ -286,6 +299,52 @@ constexpr list< T, Resource >::list ( std::initializer_list< T > _list_ ) UTI_NO
{}
#endif // UTI_HAS_STL

template< typename T, typename Resource >
constexpr
list< T, Resource >::list ( list const & _other_ ) UTI_NOEXCEPT_UNLESS_BADALLOC
: list( _other_.begin(), _other_.end() )
{}

template< typename T, typename Resource >
constexpr
list< T, Resource >::list ( list && _other_ ) noexcept
: head_( _other_.head_ )
, tail_( _other_.tail_ )
, size_( _other_.size_ )
{
_other_.head_ = _other_.tail_ = nullptr ;
_other_.size_ = 0 ;
}

template< typename T, typename Resource >
constexpr
list< T, Resource > &
list< T, Resource >::operator= ( list const & _other_ ) UTI_NOEXCEPT_UNLESS_BADALLOC
{
clear() ;

append( _other_.begin(), _other_.end() ) ;

return *this ;
}

template< typename T, typename Resource >
constexpr
list< T, Resource > &
list< T, Resource >::operator= ( list && _other_ ) noexcept
{
clear() ;

head_ = _other_.head_ ;
tail_ = _other_.tail_ ;
size_ = _other_.size_ ;

_other_.head_ = _other_.tail_ = nullptr ;
_other_.size_ = 0 ;

return *this ;
}

template< typename T, typename Resource >
constexpr void
list< T, Resource >::push_back ( value_type const & _val_ ) UTI_NOEXCEPT_UNLESS_BADALLOC
Expand Down Expand Up @@ -385,6 +444,27 @@ list< T, Resource >::insert ( iterator _position_, Args&&... _args_ ) UTI_NOEXCE
}
}

template< typename T, typename Resource >
template< meta::forward_iterator Iter >
requires meta::convertible_to< iter_value_t< Iter >, T >
constexpr void
list< T, Resource >::append ( Iter _begin_, Iter const _end_ ) UTI_NOEXCEPT_UNLESS_BADALLOC
{
for( ; _begin_ != _end_; ++_begin_ )
{
emplace_back( *_begin_ ) ;
}
}

template< typename T, typename Resource >
template< meta::simple_container Other >
requires meta::convertible_to< typename Other::value_type, T >
constexpr void
list< T, Resource >::append ( Other const & _other_ ) UTI_NOEXCEPT_UNLESS_BADALLOC
{
append( _other_.begin(), _other_.end() ) ;
}

template< typename T, typename Resource >
constexpr void
list< T, Resource >::pop_back () noexcept
Expand Down
Loading

0 comments on commit 62f95b2

Please sign in to comment.