2016-11-19 17:24:52 +00:00
/*
2018-09-02 00:57:29 +00:00
* This file is part of the DXX - Rebirth project < https : //www.dxx-rebirth.com/>.
2016-11-19 17:24:52 +00:00
* It is copyright by its individual contributors , as recorded in the
* project ' s Git history . See COPYING . txt at the top level for license
* terms and a link to the Git history .
*/
# pragma once
# include <inttypes.h>
2019-06-27 03:26:20 +00:00
# include <iterator>
2016-11-19 17:24:52 +00:00
# include "dxxsconf.h"
# include "partial_range.h"
2019-05-04 18:27:36 +00:00
# include "ephemeral_range.h"
2020-05-02 21:18:43 +00:00
# include <tuple>
# include <type_traits>
2016-11-19 17:24:52 +00:00
/*
* This could have been done using a std : : pair , but using a custom type
* allows for more descriptive member names .
*/
template < typename range_value_type , typename index_type >
struct enumerated_value
{
2019-05-04 18:27:36 +00:00
range_value_type value ;
2016-11-19 17:24:52 +00:00
const index_type idx ;
} ;
2020-05-02 21:18:43 +00:00
namespace d_enumerate {
namespace detail {
template < typename result_type , typename index_type >
struct adjust_iterator_dereference_type : std : : false_type
{
using value_type = enumerated_value < result_type , index_type > ;
} ;
template < typename . . . T , typename index_type >
struct adjust_iterator_dereference_type < std : : tuple < T . . . > , index_type > : std : : true_type
{
using value_type = std : : tuple < index_type , T . . . > ;
} ;
}
}
template < typename range_iterator_type , typename index_type , typename iterator_dereference_type >
2020-05-02 21:18:43 +00:00
class enumerated_iterator
2016-11-19 17:24:52 +00:00
{
range_iterator_type m_iter ;
index_type m_idx ;
2020-05-02 21:18:43 +00:00
using adjust_iterator_dereference_type = d_enumerate : : detail : : adjust_iterator_dereference_type < typename std : : remove_cv < iterator_dereference_type > : : type , index_type > ;
2016-11-19 17:24:52 +00:00
public :
2020-05-02 21:18:43 +00:00
using iterator_category = std : : forward_iterator_tag ;
2020-05-02 21:18:43 +00:00
using value_type = typename adjust_iterator_dereference_type : : value_type ;
2020-05-02 21:18:43 +00:00
using difference_type = std : : ptrdiff_t ;
2020-05-02 21:18:43 +00:00
using pointer = value_type * ;
using reference = value_type & ;
2016-11-19 17:24:52 +00:00
enumerated_iterator ( const range_iterator_type & iter , const index_type idx ) :
m_iter ( iter ) , m_idx ( idx )
{
}
2020-05-02 21:18:43 +00:00
value_type operator * ( ) const
2016-11-19 17:24:52 +00:00
{
2020-05-02 21:18:43 +00:00
if constexpr ( adjust_iterator_dereference_type : : value )
return std : : tuple_cat ( std : : tuple < index_type > ( m_idx ) , * m_iter ) ;
else
return { * m_iter , m_idx } ;
2016-11-19 17:24:52 +00:00
}
enumerated_iterator & operator + + ( )
{
+ + m_iter ;
+ + m_idx ;
return * this ;
}
bool operator ! = ( const enumerated_iterator & i ) const
{
return m_iter ! = i . m_iter ;
}
2019-08-24 18:14:16 +00:00
bool operator = = ( const enumerated_iterator & i ) const
{
return m_iter = = i . m_iter ;
}
2016-11-19 17:24:52 +00:00
} ;
template < typename range_iterator_type , typename index_type >
class enumerated_range : partial_range_t < range_iterator_type >
{
using base_type = partial_range_t < range_iterator_type > ;
2019-05-04 18:27:36 +00:00
using iterator_dereference_type = decltype ( * std : : declval < range_iterator_type > ( ) ) ;
2020-05-02 21:18:43 +00:00
using enumerated_iterator_type = enumerated_iterator <
range_iterator_type ,
index_type ,
iterator_dereference_type > ;
2016-11-19 17:24:52 +00:00
const index_type m_idx ;
public :
2019-05-04 18:27:36 +00:00
using range_owns_iterated_storage = std : : false_type ;
2016-11-19 17:24:52 +00:00
enumerated_range ( const range_iterator_type b , const range_iterator_type e , const index_type i ) :
base_type ( b , e ) , m_idx ( i )
{
}
template < typename range_type >
2019-05-04 18:27:36 +00:00
enumerated_range ( range_type & & t , const index_type i ) :
2016-11-19 17:24:52 +00:00
base_type ( t ) , m_idx ( i )
{
2019-05-04 18:27:36 +00:00
static_assert ( std : : is_rvalue_reference < range_type & & > : : value | | std : : is_lvalue_reference < iterator_dereference_type > : : value , " lvalue range must produce lvalue reference enumerated_value " ) ;
2016-11-19 17:24:52 +00:00
}
enumerated_iterator_type begin ( ) const
{
return enumerated_iterator_type ( this - > base_type : : begin ( ) , m_idx ) ;
}
enumerated_iterator_type end ( ) const
{
return enumerated_iterator_type ( this - > base_type : : end ( ) , 0 /* unused */ ) ;
}
} ;
template < typename range_type , typename index_type = uint_fast32_t , typename range_iterator_type = decltype ( begin ( std : : declval < range_type & > ( ) ) ) >
2019-05-04 18:27:36 +00:00
static auto enumerate ( range_type & & r , const index_type start = 0 )
2016-11-19 17:24:52 +00:00
{
2019-05-04 18:27:36 +00:00
static_assert ( ! any_ephemeral_range < range_type & & > : : value , " cannot enumerate storage of ephemeral ranges " ) ;
return enumerated_range < range_iterator_type , index_type > ( std : : forward < range_type > ( r ) , start ) ;
2016-11-19 17:24:52 +00:00
}