diff --git a/include/blt/iterator/iter_common.h b/include/blt/iterator/iter_common.h
new file mode 100644
index 0000000..89f020e
--- /dev/null
+++ b/include/blt/iterator/iter_common.h
@@ -0,0 +1,30 @@
+#pragma once
+/*
+ * Copyright (C) 2024 Brett Terpstra
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef BLT_ITERATOR_ITER_COMMON
+#define BLT_ITERATOR_ITER_COMMON
+
+#include
+#include
+
+namespace blt
+{
+
+}
+
+#endif //BLT_ITERATOR_ITER_COMMON
diff --git a/include/blt/iterator/iterator.h b/include/blt/iterator/iterator.h
new file mode 100644
index 0000000..5f9e9a7
--- /dev/null
+++ b/include/blt/iterator/iterator.h
@@ -0,0 +1,885 @@
+#pragma once
+/*
+ * Copyright (C) 2024 Brett Terpstra
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef BLT_ITERATOR_H
+#define BLT_ITERATOR_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace blt
+{
+
+ // forward declare useful types
+ template>
+ class enumerator;
+
+ template>
+ class enumerator_rev;
+
+ template>
+ class pair_iterator;
+
+ template>
+ class pair_iterator_rev;
+
+ template
+ class zip_iterator;
+
+ template
+ class zip_iterator_rev;
+
+ namespace iterator
+ {
+ template>
+ class enumerate_wrapper;
+
+ template>
+ class pair_wrapper;
+
+ template
+ class zip_wrapper;
+
+ template
+ class zip_iterator_storage;
+
+ template
+ class zip_iterator_storage_rev;
+
+ template
+ class zip_forward_iterator
+ {
+ public:
+ explicit zip_forward_iterator(Iter... iter): iter(std::make_tuple(iter...))
+ {}
+
+ std::tuple...> operator*() const
+ {
+ return std::apply([](auto& ... i) { return std::make_tuple(*i...); }, iter);
+ }
+
+ friend bool operator==(const zip_forward_iterator& a, const zip_forward_iterator& b)
+ {
+ return a.iter == b.iter;
+ }
+
+ friend bool operator!=(const zip_forward_iterator& a, const zip_forward_iterator& b)
+ {
+ return !(a.iter == b.iter);
+ }
+
+ zip_forward_iterator& operator++()
+ {
+ std::apply([](auto& ... i) { ((++i), ...); }, iter);
+ return *this;
+ }
+
+ zip_forward_iterator operator++(int)
+ {
+ auto tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ auto base()
+ {
+ return iter;
+ }
+
+ protected:
+ std::tuple iter;
+ };
+
+ template
+ class zip_bidirectional_iterator : public zip_forward_iterator
+ {
+ public:
+ using zip_forward_iterator::zip_forward_iterator;
+
+ zip_bidirectional_iterator& operator--()
+ {
+ std::apply([](auto& ... i) { ((--i), ...); }, this->iter);
+ return *this;
+ }
+
+ zip_bidirectional_iterator operator--(int)
+ {
+ auto tmp = *this;
+ --*this;
+ return tmp;
+ }
+ };
+
+ template
+ class zip_wrapper : public zip_forward_iterator
+ {
+ public:
+ using zip_forward_iterator::zip_forward_iterator;
+
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = std::tuple...>;
+ using difference_type = blt::ptrdiff_t;
+ using pointer = value_type;
+ using reference = value_type;
+ };
+
+ template
+ class zip_wrapper : public zip_bidirectional_iterator
+ {
+ public:
+ using zip_bidirectional_iterator::zip_bidirectional_iterator;
+
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = std::tuple...>;
+ using difference_type = blt::ptrdiff_t;
+ using pointer = value_type;
+ using reference = value_type;
+ };
+
+ template
+ class zip_wrapper : public zip_bidirectional_iterator
+ {
+ public:
+ using zip_bidirectional_iterator::zip_bidirectional_iterator;
+
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = std::tuple...>;
+ using difference_type = blt::ptrdiff_t;
+ using pointer = value_type;
+ using reference = value_type;
+ };
+
+ /**
+ * struct which is returned by the enumerator.
+ * @tparam T type to store.
+ */
+ template
+ struct enumerate_item
+ {
+ blt::size_t index;
+ T value;
+ };
+
+ /**
+ * base class for iterators which operate on pairs of values. Handles comparison.
+ * @tparam Iter1 first iterator type. this will be used for comparison.
+ * @tparam Iter2 second iterator type. this value is not modified by this class.
+ */
+ template
+ class dual_iterator_base
+ {
+ public:
+ explicit dual_iterator_base(Iter1 iter1, Iter2 iter2): m_iter1(std::move(iter1)), m_iter2(std::move(iter2))
+ {}
+
+ friend bool operator==(const dual_iterator_base& a, const dual_iterator_base& b)
+ {
+ return a.m_iter1 == b.m_iter1;
+ }
+
+ friend bool operator!=(const dual_iterator_base& a, const dual_iterator_base& b)
+ {
+ return a.m_iter1 != b.m_iter1;
+ }
+
+ auto iter1() const
+ {
+ return m_iter1;
+ }
+
+ auto iter2() const
+ {
+ return m_iter2;
+ }
+
+ protected:
+ Iter1 m_iter1;
+ Iter2 m_iter2;
+ };
+
+ /**
+ * Base class for all enumerator iterators. Handles the deference (*) operator.
+ * @tparam Iter iterator type
+ */
+ template
+ class enumerate_iterator_base : public dual_iterator_base
+ {
+ public:
+ explicit enumerate_iterator_base(Iter iter, blt::size_t place = 0):
+ dual_iterator_base(std::move(iter), place)
+ {}
+
+ enumerate_item> operator*() const
+ {
+ return {this->m_iter2, *this->m_iter1};
+ }
+ };
+
+ template
+ class pair_iterator_base : public dual_iterator_base
+ {
+ public:
+ using dual_iterator_base::dual_iterator_base;
+
+ std::pair, blt::meta::deref_return_t> operator*() const
+ {
+ return {*this->m_iter1, *this->m_iter2};
+ }
+ };
+
+ /**
+ * Forward iterator base class. Contains the ++ operator.
+ * @tparam Base iterator base type.
+ */
+ template
+ class forward_iterator_base : public Base
+ {
+ public:
+ using Base::Base;
+
+ forward_iterator_base& operator++()
+ {
+ ++this->m_iter1;
+ ++this->m_iter2;
+ return *this;
+ }
+
+ forward_iterator_base operator++(int)
+ {
+ auto tmp = *this;
+ ++*this;
+ return tmp;
+ }
+ };
+
+ /**
+ * Bidirectional iterator base class. Contains the -- operator.
+ * @tparam Base iterator base type.
+ */
+ template
+ class bidirectional_iterator_base : public Base
+ {
+ public:
+ using Base::Base;
+
+ bidirectional_iterator_base& operator--()
+ {
+ --this->m_iter1;
+ --this->m_iter2;
+ return *this;
+ }
+
+ bidirectional_iterator_base operator--(int)
+ {
+ auto tmp = *this;
+ --*this;
+ return tmp;
+ }
+ };
+
+ template
+ using enumerate_forward_iterator = forward_iterator_base>;
+
+ template
+ using enumerate_bidirectional_iterator = bidirectional_iterator_base>;
+
+ template
+ using pair_forward_iterator = forward_iterator_base>;
+
+ template
+ using pair_bidirectional_iterator = bidirectional_iterator_base>;
+
+ /**
+ * Enumerator wrapper class specialization for forward iterators.
+ * @tparam Iter iterator type
+ */
+ template
+ class enumerate_wrapper, std::void_t>>
+ : public enumerate_forward_iterator
+ {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = enumerate_item>;
+ using difference_type = typename std::iterator_traits::difference_type;
+ using pointer = value_type;
+ using reference = value_type;
+
+ using enumerate_forward_iterator::enumerate_forward_iterator;
+ };
+
+ /**
+ * Pair wrapper class specialization for forward iterators.
+ * @tparam Iter iterator type
+ */
+ template
+ class pair_wrapper>,
+ std::void_t>> : public pair_forward_iterator
+ {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = std::pair, blt::meta::deref_return_t>;
+ using difference_type = std::common_type_t::difference_type, typename std::iterator_traits::difference_type>;
+ using pointer = value_type;
+ using reference = value_type;
+
+ using pair_forward_iterator::pair_forward_iterator;
+ };
+
+ /**
+ * Enumerator wrapper class for bidirectional iterators or random access iterators.
+ * @tparam Iter iterator type.
+ */
+ template
+ class enumerate_wrapper, std::void_t>>
+ : public enumerate_bidirectional_iterator
+ {
+ public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = enumerate_item>;
+ using difference_type = typename std::iterator_traits::difference_type;
+ using pointer = value_type;
+ using reference = value_type;
+
+ using enumerate_bidirectional_iterator::enumerate_bidirectional_iterator;
+ };
+
+ /**
+ * Pair wrapper class for bidirectional iterators or random access iterators.
+ * @tparam Iter iterator type.
+ */
+ template
+ class pair_wrapper>,
+ std::void_t>> : public pair_bidirectional_iterator
+ {
+ public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = std::pair, blt::meta::deref_return_t>;
+ using difference_type = std::common_type_t::difference_type, typename std::iterator_traits::difference_type>;
+ using pointer = value_type;
+ using reference = value_type;
+
+ using pair_bidirectional_iterator::pair_bidirectional_iterator;
+ };
+
+ /**
+ * Base class for storing begin/end iterators.
+ * @tparam IterWrapper wrapper used to iterate
+ * @tparam CompleteClass completed class returned from skip/take methods
+ */
+ template
+ class iterator_storage_base
+ {
+ public:
+ explicit iterator_storage_base(IterWrapper begin, IterWrapper end): begin_(std::move(begin)), end_(std::move(end))
+ {}
+
+ auto begin()
+ {
+ return begin_;
+ }
+
+ auto end()
+ {
+ return end_;
+ }
+
+ /**
+ * Creates an enumerator that skips the first n elements.
+ * @param amount amount of values to skip.
+ */
+ auto skip(blt::size_t amount)
+ {
+ auto begin = this->begin_;
+ for (blt::size_t i = 0; i < amount; i++)
+ ++begin;
+ return CompleteClass{begin.iter1(),
+ this->end_.iter1(),
+ begin.iter2(),
+ this->end_.iter2()};
+ }
+
+ /**
+ * Creates an enumerator that yields the first n elements, or UB if the underlying iterator ends sooner.
+ * @param amount amount to take.
+ */
+ auto take(blt::size_t amount)
+ {
+ auto end = this->begin();
+ for (blt::size_t i = 0; i < amount; i++)
+ ++end;
+ return CompleteClass{this->begin_.iter1(),
+ end.iter1(),
+ this->begin_.iter2(),
+ end.iter2()};
+ }
+
+ protected:
+ IterWrapper begin_;
+ IterWrapper end_;
+ };
+
+ /**
+ * Reversible (bidirectional) base class storing the begin / end iterators.
+ * @tparam Iter iterator type.
+ * @tparam IterWrapper wrapper used to iterate.
+ * @tparam CompleteClass completed class returned from skip/take methods
+ * @tparam CompleteClassRev reverse version of CompleteClass, returned from rev
+ */
+ template
+ class iterator_storage_reversible : public iterator_storage_base
+ {
+ public:
+ explicit iterator_storage_reversible(IterWrapper begin, IterWrapper end):
+ iterator_storage_base{std::move(begin), std::move(end)}
+ {}
+
+ /**
+ * Reverses the enumerator’s direction.
+ */
+ auto rev() const
+ {
+ return CompleteClassRev{this->end_.iter1(),
+ this->begin_.iter1(),
+ this->end_.iter2(),
+ this->begin_.iter2()};
+ }
+ };
+
+ /**
+ * Random access base class storage for begin/end iterators.
+ * Has updated skip and take methods which make use of the random access nature of the iterator.
+ * @tparam Iter iterator type.
+ * @tparam IterWrapper wrapper used to iterate.
+ * @tparam CompleteClass completed class returned from skip/take methods
+ * @tparam CompleteClassRev reverse version of CompleteClass, returned from rev
+ */
+ template
+ class iterator_storage_random_access : public iterator_storage_reversible
+ {
+ public:
+ using iterator_storage_reversible::iterator_storage_reversible;
+
+ auto skip(blt::size_t amount)
+ {
+ return CompleteClass{this->begin_.iter1() + amount,
+ this->end_.iter1(),
+ this->begin_.iter2() + amount,
+ this->end_.iter2()};
+ }
+
+ auto take(blt::size_t amount)
+ {
+ return CompleteClass{this->begin_.iter1(),
+ this->begin_.iter1() + amount,
+ this->begin_.iter2(),
+ this->begin_.iter2() + amount};
+ }
+ };
+
+ /**
+ * Reversible (bidirectional) base class for storing the begin/end iterators, operates in reverse for reverse iteration.
+ * @tparam Iter iterator type.
+ * @tparam IterWrapper wrapper used to iterate (std::reverse_iterator).
+ * @tparam CompleteClass completed class returned from skip/take methods
+ * @tparam CompleteClassRev reverse version of CompleteClass, returned from rev
+ */
+ template
+ class iterator_storage_reversible_rev : public iterator_storage_reversible
+ {
+ public:
+ using iterator_storage_reversible::iterator_storage_reversible;
+
+ auto rev() const
+ {
+ return CompleteClass{this->end_.base().iter1(),
+ this->begin_.base().iter1(),
+ this->end_.base().iter2(),
+ this->begin_.base().iter2()};
+ }
+
+ auto skip(blt::size_t amount)
+ {
+ auto begin = this->begin_.base();
+ for (blt::size_t i = 0; i < amount; i++)
+ --begin;
+ return CompleteClassRev{begin.iter1(),
+ this->end_.base().iter1(),
+ begin.iter2(),
+ this->end_.base().iter2()};
+ }
+
+ auto take(blt::size_t amount)
+ {
+ auto end = this->begin_.base();
+ for (blt::size_t i = 0; i < amount; i++)
+ --end;
+ return CompleteClassRev{
+ this->begin_.base().iter1(),
+ end.iter1(),
+ this->begin_.base().iter2(),
+ end.iter2()};
+ }
+ };
+
+ /**
+ * Random access base class for storing the begin/end iterator.
+ * Has updated skip and take methods which make use of the random access nature of the iterator.
+ * Operates in reverse for reverse iteration.
+ * @tparam Iter iterator type.
+ * @tparam IterWrapper wrapper used to iterate (std::reverse_iterator).
+ * @tparam CompleteClass completed class returned from skip/take methods
+ * @tparam CompleteClassRev reverse version of CompleteClass, returned from rev
+ */
+ template
+ class iterator_storage_random_access_rev : public iterator_storage_reversible_rev
+ {
+ public:
+ using iterator_storage_reversible_rev::iterator_storage_reversible_rev;
+
+ auto skip(blt::size_t amount)
+ {
+ return CompleteClassRev{this->begin_.base().iter1() - amount,
+ this->end_.base().iter1(),
+ this->begin_.base().iter2() - amount,
+ this->end_.base().iter2()};
+ }
+
+ auto take(blt::size_t amount)
+ {
+ return CompleteClassRev{this->begin_.base().iter1(),
+ this->begin_.base().iter1() - amount,
+ this->begin_.base().iter2(),
+ this->begin_.base().iter2() - amount};
+ }
+ };
+
+ /**
+ * Base class for types which can be converted to an enumerator
+ */
+ template
+ class enumerator_convertible
+ {
+ public:
+ auto enumerate()
+ {
+ auto* b = static_cast(this);
+ return CompleteEnumerator{b->begin(), b->end(), static_cast(std::distance(b->begin(), b->end()))};
+ }
+ };
+
+ template
+ class zip_iterator_storage
+ {
+
+ };
+
+ template
+ class zip_iterator_storage
+ {
+
+ };
+
+ template
+ class zip_iterator_storage
+ {
+
+ };
+
+ }
+
+ /**
+ * Enumerator specialization for forward iterators
+ */
+ template
+ class enumerator, std::void_t>>
+ : public iterator::iterator_storage_base, enumerator>
+ {
+ public:
+ explicit enumerator(Iter begin, Iter end, blt::size_t container_size):
+ iterator::iterator_storage_base, enumerator>
+ {iterator::enumerate_wrapper{std::move(begin), 0},
+ iterator::enumerate_wrapper{std::move(end), container_size}}
+ {}
+
+ explicit enumerator(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
+ iterator::iterator_storage_base, enumerator>{
+ iterator::enumerate_wrapper{std::move(begin), begin_index},
+ iterator::enumerate_wrapper{std::move(end), end_index}}
+ {}
+ };
+
+ /**
+ * Enumerator specialization for bidirectional iterators
+ */
+ template
+ class enumerator, std::void_t>>
+ : public iterator::iterator_storage_reversible, enumerator, enumerator_rev>
+ {
+ public:
+ explicit enumerator(Iter begin, Iter end, blt::size_t container_size):
+ iterator::iterator_storage_reversible, enumerator, enumerator_rev>
+ {iterator::enumerate_wrapper{std::move(begin), 0},
+ iterator::enumerate_wrapper{std::move(end), container_size}}
+ {}
+
+ explicit enumerator(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
+ iterator::iterator_storage_reversible, enumerator, enumerator_rev>{
+ iterator::enumerate_wrapper{std::move(begin), begin_index},
+ iterator::enumerate_wrapper{std::move(end), end_index}}
+ {}
+ };
+
+ /**
+ * Enumerator specialization for random access iterators
+ */
+ template
+ class enumerator, std::void_t>>
+ : public iterator::iterator_storage_random_access, enumerator, enumerator_rev>
+ {
+ public:
+ explicit enumerator(Iter begin, Iter end, blt::size_t container_size):
+ iterator::iterator_storage_random_access, enumerator, enumerator_rev>
+ {iterator::enumerate_wrapper{std::move(begin), 0},
+ iterator::enumerate_wrapper{std::move(end), container_size}}
+ {}
+
+ explicit enumerator(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
+ iterator::iterator_storage_random_access, enumerator, enumerator_rev>{
+ iterator::enumerate_wrapper{std::move(begin), begin_index},
+ iterator::enumerate_wrapper{std::move(end), end_index}}
+ {}
+ };
+
+ /**
+ * Reverse enumerator specialization for bidirectional iterators
+ */
+ template
+ class enumerator_rev, std::void_t>>
+ : public iterator::iterator_storage_reversible_rev>, enumerator, enumerator_rev>
+ {
+ public:
+ explicit enumerator_rev(Iter begin, Iter end, blt::size_t container_size):
+ iterator::iterator_storage_reversible_rev>, enumerator, enumerator_rev>
+ {std::reverse_iterator>{iterator::enumerate_wrapper{std::move(begin), 0}},
+ std::reverse_iterator>{
+ iterator::enumerate_wrapper{std::move(end), container_size}}}
+ {}
+
+ explicit enumerator_rev(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
+ iterator::iterator_storage_reversible_rev>, enumerator, enumerator_rev>{
+ std::reverse_iterator>{
+ iterator::enumerate_wrapper{std::move(begin), begin_index}},
+ std::reverse_iterator>{iterator::enumerate_wrapper{std::move(end), end_index}}}
+ {}
+ };
+
+ /**
+ * Reverse enumerator specialization for random access iterators
+ */
+ template
+ class enumerator_rev, std::void_t>>
+ : public iterator::iterator_storage_random_access_rev>, enumerator, enumerator_rev>
+ {
+ public:
+ explicit enumerator_rev(Iter begin, Iter end, blt::size_t container_size):
+ iterator::iterator_storage_random_access_rev>, enumerator, enumerator_rev>
+ {std::reverse_iterator>{iterator::enumerate_wrapper{std::move(begin), 0}},
+ std::reverse_iterator>{
+ iterator::enumerate_wrapper{std::move(end), container_size}}}
+ {}
+
+ explicit enumerator_rev(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
+ iterator::iterator_storage_random_access_rev>, enumerator, enumerator_rev>{
+ std::reverse_iterator>{
+ iterator::enumerate_wrapper{std::move(begin), begin_index}},
+ std::reverse_iterator>{iterator::enumerate_wrapper{std::move(end), end_index}}}
+ {}
+ };
+
+ // CTAD for enumerators
+
+ template
+ enumerator(Iter, Iter) -> enumerator;
+
+ template
+ enumerator(Iter, Iter, blt::size_t) -> enumerator;
+
+ template
+ enumerator(Iter, Iter, blt::size_t, blt::size_t) -> enumerator;
+
+ template
+ class pair_iterator>,
+ std::void_t>>
+ : public iterator::iterator_storage_base, pair_iterator>,
+ public iterator::enumerator_convertible, enumerator>>
+ {
+ public:
+ explicit pair_iterator(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2):
+ iterator::iterator_storage_base, pair_iterator>
+ {iterator::pair_wrapper{std::move(begin1), std::move(begin2)},
+ iterator::pair_wrapper{std::move(end1), std::move(end2)}}
+ {}
+ };
+
+ template
+ class pair_iterator>,
+ std::void_t>>
+ : public iterator::iterator_storage_reversible, pair_iterator, pair_iterator_rev>,
+ public iterator::enumerator_convertible, enumerator>>
+ {
+ public:
+ explicit pair_iterator(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2):
+ iterator::iterator_storage_reversible, pair_iterator, pair_iterator_rev>
+ {iterator::pair_wrapper{std::move(begin1), std::move(begin2)},
+ iterator::pair_wrapper{std::move(end1), std::move(end2)}}
+ {}
+ };
+
+ template
+ class pair_iterator>,
+ std::void_t>>
+ : public iterator::iterator_storage_random_access, pair_iterator, pair_iterator_rev>,
+ public iterator::enumerator_convertible, enumerator>>
+ {
+ public:
+ explicit pair_iterator(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2):
+ iterator::iterator_storage_random_access, pair_iterator, pair_iterator_rev>
+ {iterator::pair_wrapper{std::move(begin1), std::move(begin2)},
+ iterator::pair_wrapper{std::move(end1), std::move(end2)}}
+ {}
+ };
+
+ template
+ class pair_iterator_rev>,
+ std::void_t>>
+ : public iterator::iterator_storage_reversible_rev>, pair_iterator, pair_iterator_rev>,
+ public iterator::enumerator_convertible