iterator: modify to allow iteration over c arrays
This commit is contained in:
parent
c222e4e960
commit
9c5b471b24
93
iterator.hpp
93
iterator.hpp
@ -216,25 +216,31 @@ namespace util {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
namespace detail::zip {
|
namespace detail::zip {
|
||||||
|
// holds a tuple of iterators for begin and end, and returns an
|
||||||
|
// iterator that transforms these iterators into tuples of value_types.
|
||||||
|
//
|
||||||
|
// this must be expressed in terms of iterators, rather than containers,
|
||||||
|
// because it dramatically simplifies iterating over raw arrays.
|
||||||
template <
|
template <
|
||||||
typename ContainerT,
|
|
||||||
typename IteratorT,
|
typename IteratorT,
|
||||||
typename I = std::make_index_sequence<std::tuple_size<ContainerT>::value>
|
typename I = std::make_index_sequence<std::tuple_size<IteratorT>::value>
|
||||||
>
|
>
|
||||||
struct collection;
|
class collection;
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------
|
||||||
template <
|
template <
|
||||||
typename ContainerT,
|
|
||||||
typename IteratorT,
|
typename IteratorT,
|
||||||
std::size_t ...I
|
std::size_t ...I
|
||||||
>
|
>
|
||||||
struct collection<
|
class collection<
|
||||||
ContainerT,
|
|
||||||
IteratorT,
|
IteratorT,
|
||||||
std::index_sequence<I...>
|
std::index_sequence<I...>
|
||||||
> {
|
> {
|
||||||
collection (const ContainerT &_containers):
|
public:
|
||||||
m_containers { _containers }
|
collection (const IteratorT &_begin, const IteratorT &_end):
|
||||||
|
m_begin { _begin },
|
||||||
|
m_end { _end }
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
struct iterator : std::iterator<
|
struct iterator : std::iterator<
|
||||||
@ -246,13 +252,14 @@ namespace util {
|
|||||||
>,
|
>,
|
||||||
std::size_t
|
std::size_t
|
||||||
> {
|
> {
|
||||||
IteratorT m_iterators;
|
public:
|
||||||
|
iterator (const IteratorT &_iterators):
|
||||||
iterator (IteratorT _iterators):
|
|
||||||
m_iterators (_iterators)
|
m_iterators (_iterators)
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
iterator& operator++ (void)
|
|
||||||
|
iterator&
|
||||||
|
operator++ (void)
|
||||||
{
|
{
|
||||||
// HACK: we don't actually need to create a tuple here,
|
// HACK: we don't actually need to create a tuple here,
|
||||||
// but it's a zero cost method to expand the parameter
|
// but it's a zero cost method to expand the parameter
|
||||||
@ -261,58 +268,86 @@ namespace util {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
iterator operator++ (int);
|
iterator operator++ (int);
|
||||||
|
|
||||||
auto operator* (void)
|
|
||||||
|
auto
|
||||||
|
operator* (void)
|
||||||
{
|
{
|
||||||
return std::make_tuple (*std::get<I> (m_iterators)...);
|
return std::make_tuple (*std::get<I> (m_iterators)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator== (const iterator &rhs) const
|
|
||||||
|
bool
|
||||||
|
operator== (const iterator &rhs) const
|
||||||
{
|
{
|
||||||
return m_iterators == rhs.m_iterators;
|
return m_iterators == rhs.m_iterators;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!= (const iterator &rhs) const
|
|
||||||
|
bool
|
||||||
|
operator!= (const iterator &rhs) const
|
||||||
{
|
{
|
||||||
return !(*this == rhs);
|
return !(*this == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
IteratorT m_iterators;
|
||||||
};
|
};
|
||||||
|
|
||||||
iterator begin (void)
|
|
||||||
|
iterator
|
||||||
|
begin (void)
|
||||||
{
|
{
|
||||||
return iterator { { std::begin (std::get<I> (m_containers))... } };
|
return iterator { { std::get<I> (m_begin)... } };
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator end (void)
|
|
||||||
|
iterator
|
||||||
|
end (void)
|
||||||
{
|
{
|
||||||
return iterator { { std::end (std::get<I> (m_containers))... } };
|
return iterator { { std::get<I> (m_end)... } };
|
||||||
}
|
}
|
||||||
|
|
||||||
ContainerT m_containers;
|
|
||||||
|
private:
|
||||||
|
IteratorT m_begin;
|
||||||
|
IteratorT m_end;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
///------------------------------------------------------------------------
|
||||||
|
/// takes a variable number of container arguments and returns an interable
|
||||||
|
/// object with a value_type of tuple of the argument's value_types.
|
||||||
|
///
|
||||||
|
/// the returned iterator value_type is suitable for using in range-for
|
||||||
|
/// and structured bindings (and really, that's the entire point here).
|
||||||
|
///
|
||||||
|
/// eg, util::zip ({1,2,3}, {4,5,6}) ~= {{1,4},{2,5},{3,6}}
|
||||||
template <typename ...ContainerT>
|
template <typename ...ContainerT>
|
||||||
auto
|
auto
|
||||||
zip (const ContainerT&... data)
|
zip (const ContainerT&... data)
|
||||||
{
|
{
|
||||||
using container = std::tuple<ContainerT...>;
|
using IteratorT = std::tuple<decltype(std::begin(data))...>;
|
||||||
using iterator = std::tuple<decltype(std::begin(data))...>;
|
|
||||||
|
|
||||||
return detail::zip::collection<
|
return detail::zip::collection<
|
||||||
container,
|
IteratorT,
|
||||||
iterator,
|
|
||||||
std::make_index_sequence<sizeof...(ContainerT)>
|
std::make_index_sequence<sizeof...(ContainerT)>
|
||||||
> (
|
> {
|
||||||
std::make_tuple (data...)
|
std::make_tuple (std::begin (data)...),
|
||||||
);
|
std::make_tuple (std::end (data)...)
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
///------------------------------------------------------------------------
|
||||||
|
/// takes a variable number of containers and returns a zipped iterable
|
||||||
|
/// object where the first of the iterator's value_types is the index of
|
||||||
|
/// that iterator. ie, it combines container offsets with value_types.
|
||||||
|
///
|
||||||
|
/// eg, util::izip ("abc") ~= {{0,'a'},{1,'b'},{2,'c'}}
|
||||||
template <typename ...ContainerT>
|
template <typename ...ContainerT>
|
||||||
auto
|
auto
|
||||||
izip (const ContainerT&... data)
|
izip (const ContainerT&... data)
|
||||||
|
@ -14,12 +14,16 @@ main (int, char**)
|
|||||||
|
|
||||||
std::vector<int> v_int { 1, 2, 3 };
|
std::vector<int> v_int { 1, 2, 3 };
|
||||||
std::array<float,3> a_float { 1.1f, 2.2f, 3.3f };
|
std::array<float,3> a_float { 1.1f, 2.2f, 3.3f };
|
||||||
|
char c_char[] = { 'a', 'b', 'c' };
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
for (auto [i, v, a]: util::izip (v_int, a_float)) {
|
for (auto [i, v, a, c]: util::izip (v_int, a_float, c_char)) {
|
||||||
success = success && v_int[i] == v && util::exactly_equal (a_float[i], a);
|
success = success &&
|
||||||
|
v_int[i] == v &&
|
||||||
|
util::exactly_equal (a_float[i], a) &&
|
||||||
|
c_char[i] == c;
|
||||||
}
|
}
|
||||||
|
|
||||||
tap.expect (success, "izip tuples of int and float");
|
tap.expect (success, "izip containers of int, float, and char and an initialiser_list");
|
||||||
return tap.status ();
|
return tap.status ();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user