Skip to content

Instantly share code, notes, and snippets.

@k06a
Last active May 24, 2018 14:31
Show Gist options
  • Save k06a/d1529ebf1ebbdbde98b3c01cf7e8cbfb to your computer and use it in GitHub Desktop.
Save k06a/d1529ebf1ebbdbde98b3c01cf7e8cbfb to your computer and use it in GitHub Desktop.
Iterator over std::vector of containers (std::vector, std::list, std::deque)
#include <iostream>
#include <list>
#include <deque>
#include <vector>
// Can use mpark instead of std: https://github.com/mpark/variant
//#include "variant.hpp"
#include <variant>
//
template<typename T>
struct MetaContainer {
typedef std::variant<
std::list<T>,
std::deque<T>,
std::vector<T>
> element_type;
typedef std::variant<
typename std::list<T>::iterator,
typename std::deque<T>::iterator,
typename std::vector<T>::iterator
> iterator_type;
};
template<typename T>
class MetaIterator : public std::iterator<std::forward_iterator_tag, T>
{
typedef std::vector<typename MetaContainer<T>::iterator_type> vector_of_iterators_type;
int index;
vector_of_iterators_type its;
vector_of_iterators_type ends;
public:
MetaIterator(const vector_of_iterators_type & its,
const vector_of_iterators_type & ends)
: index()
, its(its)
, ends(ends)
{
assert(its.size() == ends.size());
}
MetaIterator(const MetaIterator & it)
: index(it.index)
, its(it.its)
, ends(it.ends)
{
}
MetaIterator & operator++() {
while (index < its.size() && its[index] == ends[index]) {
++index;
};
std::visit([](auto & elem) { ++elem; }, its[index]);
while (index < its.size() && its[index] == ends[index]) {
++index;
};
return *this;
}
MetaIterator operator++(int) {
MetaIterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const MetaIterator & rhs) const {
if ((this->atEnd() && rhs.isEnd()) ||
(this->isEnd() && rhs.atEnd())) {
return true;
}
return index == rhs.index
&& its.size() == rhs.its.size()
&& its[index] == rhs.its[rhs.index];
}
bool operator!=(const MetaIterator& rhs) const {
return !operator==(rhs);
}
T & operator*() {
T *value;
std::visit([&value](auto elem) { value = &(*elem); }, its[index]);
return *value;
}
bool atEnd() const {
return index == its.size();
}
bool isEnd() const {
return its.size() == 0;
}
static MetaIterator universal_end() {
return MetaIterator(vector_of_iterators_type {},
vector_of_iterators_type {});
}
};
template<typename T, typename TMeta>
auto meta_begin(TMeta & meta) {
std::vector<typename MetaContainer<T>::iterator_type> its;
std::for_each(meta.begin(), meta.end(), [&its](auto & el){
std::visit([&its](auto & elem) { its.push_back(std::begin(elem)); }, el);
});
std::vector<typename MetaContainer<T>::iterator_type> ends;
std::for_each(meta.begin(), meta.end(), [&ends](auto & el){
std::visit([&ends](auto & elem) { ends.push_back(std::end(elem)); }, el);
});
return MetaIterator<T>(its, ends);
}
template<typename T, typename TMeta>
auto meta_end(TMeta & meta) {
return MetaIterator<T>::universal_end();
}
//
int main() {
std::vector<typename MetaContainer<int>::element_type> meta = {
std::list<int> {1,2,3},
std::deque<int> {4,5},
std::vector<int> {6,7,8,9},
};
for (auto it = meta_begin<int>(meta); it != meta_end<int>(meta); ++it) {
std::cout << *it << ' ';
}
}
1 2 3 4 5 6 7 8 9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment