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
2020-05-02 21:18:43 +00:00
namespace d_enumerate {
namespace detail {
2021-09-04 12:17:14 +00:00
/* In the general case, `value_type` is a tuple of the index and the
* result of the underlying sequence .
*
* In the special case that ` result_type ` is a tuple , construct a
* modified tuple instead of using a tuple of ( index , inner tuple ) .
* This allows simpler structured bindings .
*/
2021-06-28 03:37:50 +00:00
template < typename index_type , typename result_type >
2020-05-02 21:18:43 +00:00
struct adjust_iterator_dereference_type : std : : false_type
{
2021-06-28 03:37:50 +00:00
using value_type = std : : tuple < index_type , result_type > ;
2020-05-02 21:18:43 +00:00
} ;
2021-06-28 03:37:50 +00:00
template < typename index_type , typename . . . T >
struct adjust_iterator_dereference_type < index_type , std : : tuple < T . . . > > : std : : true_type
2020-05-02 21:18:43 +00:00
{
using value_type = std : : tuple < index_type , T . . . > ;
} ;
2021-09-04 12:17:14 +00:00
/* Retrieve the member typedef `index_type` if one exists. Otherwise,
* use ` uint_fast32_t ` as a fallback .
*/
template < typename >
uint_fast32_t array_index_type ( . . . ) ;
/* Add, then remove, a reference to the `index_type`. If `index_type`
* is an integer or enum type , this produces ` index_type ` again . If
* ` index_type ` is ` void ` , then this overload refers to
* ` std : : remove_reference < void & > : : type ` , which is ill - formed , and the
* overload is removed by SFINAE . This allows target types to use
* ` using index_type = void ` to decline to specify an ` index_type ` ,
* which may be convenient in templates that conditionally define an
* ` index_type ` based on their template parameters .
*/
template < typename T >
typename std : : remove_reference < typename std : : remove_reference < T > : : type : : index_type & > : : type array_index_type ( std : : nullptr_t ) ;
2020-05-02 21:18:43 +00:00
}
}
2022-02-13 19:13:38 +00:00
template < typename range_index_type , typename range_iterator_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 ;
2022-02-13 19:13:38 +00:00
range_index_type m_idx ;
using adjust_iterator_dereference_type = d_enumerate : : detail : : adjust_iterator_dereference_type < range_index_type , iterator_dereference_type > ;
2016-11-19 17:24:52 +00:00
public :
2022-02-13 19:13:38 +00:00
using index_type = range_index_type ;
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 & ;
2021-06-28 03:37:50 +00:00
enumerated_iterator ( range_iterator_type & & iter , const index_type idx ) :
m_iter ( std : : move ( iter ) ) , m_idx ( idx )
2016-11-19 17:24:52 +00:00
{
}
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
2021-06-28 03:37:50 +00:00
return { m_idx , * m_iter } ;
2016-11-19 17:24:52 +00:00
}
enumerated_iterator & operator + + ( )
{
+ + m_iter ;
2021-09-04 12:17:14 +00:00
if constexpr ( std : : is_enum < index_type > : : value )
/* An enum type is not required to have operator++()
* defined , and may deliberately omit it to avoid allowing
* the value to be incremented in the typical use case . For
* this situation , an increment is desired , so emulate
* operator + + ( ) by casting to the underlying integer
* type , adding 1 , and casting back .
*/
m_idx = static_cast < index_type > ( 1u + static_cast < typename std : : underlying_type < index_type > : : type > ( m_idx ) ) ;
else
+ + m_idx ;
2016-11-19 17:24:52 +00:00
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
} ;
2022-02-13 19:13:38 +00:00
template < typename range_iterator_type , typename range_index_type >
class enumerate : partial_range_t < range_iterator_type , range_index_type >
2016-11-19 17:24:52 +00:00
{
2022-02-13 19:13:38 +00:00
using base_type = partial_range_t < range_iterator_type , range_index_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 <
2022-02-13 19:13:38 +00:00
range_index_type ,
2021-06-28 03:37:50 +00:00
range_iterator_type ,
typename std : : remove_cv < iterator_dereference_type > : : type > ;
2022-02-13 19:13:38 +00:00
const range_index_type m_idx ;
2016-11-19 17:24:52 +00:00
public :
2019-05-04 18:27:36 +00:00
using range_owns_iterated_storage = std : : false_type ;
2022-02-13 19:13:38 +00:00
using typename base_type : : index_type ;
2020-07-16 02:31:04 +00:00
enumerate ( const range_iterator_type b , const range_iterator_type e , const index_type i ) :
2016-11-19 17:24:52 +00:00
base_type ( b , e ) , m_idx ( i )
{
}
template < typename range_type >
2021-06-28 03:37:50 +00:00
enumerate ( range_type & & t , const index_type i = index_type { } ) :
base_type ( std : : forward < range_type > ( t ) ) , m_idx ( i )
2016-11-19 17:24:52 +00:00
{
2020-07-16 02:31:04 +00:00
static_assert ( ! any_ephemeral_range < range_type & & > : : value , " cannot enumerate storage of ephemeral ranges " ) ;
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
{
2021-06-28 03:37:50 +00:00
return { this - > base_type : : begin ( ) , m_idx } ;
2016-11-19 17:24:52 +00:00
}
enumerated_iterator_type end ( ) const
{
2021-06-28 03:37:50 +00:00
return { this - > base_type : : end ( ) , index_type { } /* unused */ } ;
2016-11-19 17:24:52 +00:00
}
} ;
2021-09-04 12:17:14 +00:00
template < typename range_type , typename index_type = decltype ( d_enumerate : : detail : : array_index_type < range_type > ( nullptr ) ) , typename range_iterator_type = decltype ( std : : begin ( std : : declval < range_type & > ( ) ) ) >
2020-07-16 02:31:04 +00:00
enumerate ( range_type & & r , const index_type start = index_type ( /* value ignored */ ) ) - > enumerate < range_iterator_type , index_type > ;