Last active
May 24, 2018 14:31
-
-
Save k06a/d1529ebf1ebbdbde98b3c01cf7e8cbfb to your computer and use it in GitHub Desktop.
Iterator over std::vector of containers (std::vector, std::list, std::deque)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 << ' '; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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