/*
* This file is part of the DXX-Rebirth project .
* 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
#include
#include "dxxsconf.h"
#include "partial_range.h"
#include "ephemeral_range.h"
#include
#include
/*
* This could have been done using a std::pair, but using a custom type
* allows for more descriptive member names.
*/
template
struct enumerated_value
{
const index_type idx;
range_value_type value;
};
namespace d_enumerate {
namespace detail {
template
struct adjust_iterator_dereference_type : std::false_type
{
using value_type = enumerated_value;
};
template
struct adjust_iterator_dereference_type, index_type> : std::true_type
{
using value_type = std::tuple;
};
}
}
template
class enumerated_iterator
{
range_iterator_type m_iter;
index_type m_idx;
using adjust_iterator_dereference_type = d_enumerate::detail::adjust_iterator_dereference_type::type, index_type>;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = typename adjust_iterator_dereference_type::value_type;
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
using reference = value_type &;
enumerated_iterator(const range_iterator_type &iter, const index_type idx) :
m_iter(iter), m_idx(idx)
{
}
value_type operator*() const
{
if constexpr (adjust_iterator_dereference_type::value)
return std::tuple_cat(std::tuple(m_idx), *m_iter);
else
return {m_idx, *m_iter};
}
enumerated_iterator &operator++()
{
++ m_iter;
++ m_idx;
return *this;
}
bool operator!=(const enumerated_iterator &i) const
{
return m_iter != i.m_iter;
}
bool operator==(const enumerated_iterator &i) const
{
return m_iter == i.m_iter;
}
};
template
class enumerate : partial_range_t
{
using base_type = partial_range_t;
using iterator_dereference_type = decltype(*std::declval());
using enumerated_iterator_type = enumerated_iterator<
range_iterator_type,
index_type,
iterator_dereference_type>;
const index_type m_idx;
public:
using range_owns_iterated_storage = std::false_type;
enumerate(const range_iterator_type b, const range_iterator_type e, const index_type i) :
base_type(b, e), m_idx(i)
{
}
template
enumerate(range_type &&t, const index_type i = 0) :
base_type(t), m_idx(i)
{
static_assert(!any_ephemeral_range::value, "cannot enumerate storage of ephemeral ranges");
static_assert(std::is_rvalue_reference::value || std::is_lvalue_reference::value, "lvalue range must produce lvalue reference enumerated_value");
}
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 ()))>
enumerate(range_type &&r, const index_type start = index_type(/* value ignored */)) -> enumerate;