diff --git a/source/mijin/util/iterators.hpp b/source/mijin/util/iterators.hpp index b881bab..090bde8 100644 --- a/source/mijin/util/iterators.hpp +++ b/source/mijin/util/iterators.hpp @@ -5,9 +5,46 @@ #include #include +#include namespace mijin { +struct RangeAdapter {}; + +template +struct RangeRef +{ + T& range; + + decltype(auto) begin() const + { + return std::begin(range); + } + + decltype(auto) end() const + { + return std::end(range); + } +}; +template +concept RangeAdapterType = std::is_base_of_v; + +template +struct RangeRef +{ + T range; + + decltype(auto) begin() const + { + return range.begin(); + } + + decltype(auto) end() const + { + return range.end(); + } +}; + template struct EnumeratingIterator { @@ -66,9 +103,9 @@ template EnumeratingIterator(TIdx, TIterator) -> EnumeratingIterator; template -struct Enumeratable +struct Enumeratable : RangeAdapter { - TIterable& base; + RangeRef base; auto begin() const noexcept { @@ -82,9 +119,232 @@ struct Enumeratable }; template -Enumeratable enumerate(TIterable& iterable) +Enumeratable enumerate(TIterable&& iterable) { - return {iterable}; + return {.base = {std::forward(iterable)}}; +} + +template +struct ReplacingIterator +{ + using difference_type = std::ptrdiff_t; + using value_type = typename std::iterator_traits::value_type; + using pointer = std::add_const_t*; + using reference = std::add_const_t&; + using iterator_category = std::bidirectional_iterator_tag; // TODO? + + TIterator base; + value_type what; + value_type with; + + ReplacingIterator(TIterator base_, value_type what_, value_type with_) noexcept : base(base_), what(what_), with(with_) {} + ReplacingIterator(const ReplacingIterator&) noexcept = default; + + ReplacingIterator& operator=(const ReplacingIterator&) noexcept = default; + + pointer operator->() const noexcept + { + if (*base == what) { + return &with; + } + return &*base; + } + + reference operator*() const noexcept + { + if (*base == what) { + return with; + } + return *base; + } + + ReplacingIterator& operator++() noexcept + { + ++base; + return *this; + } + + ReplacingIterator operator++(int) noexcept + { + ReplacingIterator copy(*this); + ++(*this); + return copy; + } + + ReplacingIterator& operator--() noexcept + { + --base; + return *this; + } + + ReplacingIterator operator--(int) noexcept + { + EnumeratingIterator copy(*this); + --(*this); + return copy; + } + + bool operator==(const ReplacingIterator& other) const noexcept + { + return what == other.what && with == other.with && base == other.base; + } + + bool operator!=(const ReplacingIterator& other) const noexcept + { + return !(*this == other); + } +}; + +template +struct ReplacingRange : RangeAdapter +{ + using value_type = typename std::iterator_traits()))>::value_type; + + RangeRef base; + value_type what; + value_type with; + + auto begin() const noexcept + { + return ReplacingIterator(base.begin(), what, with); + } + + auto end() const noexcept + { + return ReplacingIterator(base.end(), what, with); + } +}; + +template +auto replace( + TIterable&& iterable, + typename std::iterator_traits()))>::value_type what, + typename std::iterator_traits()))>::value_type with) +{ + return ReplacingRange{ + .base = {std::forward(iterable)}, + .what = std::move(what), + .with = std::move(with) + }; +} + +template +struct ChainingIterator +{ + using difference_type = std::ptrdiff_t; + using value_type = typename std::iterator_traits::value_type; + using pointer = std::add_const_t*; + using reference = std::add_const_t&; + using iterator_category = std::bidirectional_iterator_tag; // TODO? + + TFirstIterator firstBase; + TFirstIterator firstEnd; + TSecondIterator secondBase; + TSecondIterator secondBegin; + + ChainingIterator(TFirstIterator firstBase_, TFirstIterator firstEnd_, TSecondIterator secondBase_, TSecondIterator secondBegin_) noexcept + : firstBase(firstBase_), firstEnd(firstEnd_), secondBase(secondBase_), secondBegin(secondBegin_) {} + ChainingIterator(const ChainingIterator&) noexcept = default; + + ChainingIterator& operator=(const ChainingIterator&) noexcept = default; + + pointer operator->() const noexcept + { + if (firstBase == firstEnd) + { + return &*secondBase; + } + return &*firstBase; + } + + reference operator*() const noexcept + { + if (firstBase == firstEnd) + { + return *secondBase; + } + return *firstBase; + } + + ChainingIterator& operator++() noexcept + { + if (firstBase == firstEnd) { + ++secondBase; + } + else { + ++firstBase; + } + return *this; + } + + ChainingIterator operator++(int) noexcept + { + ChainingIterator copy(*this); + ++(*this); + return copy; + } + + ChainingIterator& operator--() noexcept + { + if (secondBase == secondBegin) { + --firstBase; + } + else { + --secondBase; + } + return *this; + } + + ChainingIterator operator--(int) noexcept + { + ChainingIterator copy(*this); + --(*this); + return copy; + } + + bool operator==(const ChainingIterator& other) const noexcept + { + return firstBase == other.firstBase && secondBase == other.secondBase; // should be enough + } + + bool operator!=(const ChainingIterator& other) const noexcept + { + return !(*this == other); + } +}; + +template +struct ChainedRange : RangeAdapter +{ + using value_type = typename std::iterator_traits()))>::value_type; + + RangeRef first; + RangeRef second; + + auto begin() const noexcept + { + return ChainingIterator(first.begin(), first.end(), second.begin(), second.begin()); + } + + auto end() const noexcept + { + return ChainingIterator(first.end(), first.end(), second.end(), second.begin()); + } +}; + +template +auto chain(TFirstRange&& firstRange, TSecondRange&& secondRange) +{ + return ChainedRange{ + .first = {std::forward(firstRange)}, + .second = {std::forward(secondRange)} + }; +} + +template +auto chain(TFirstRange&& firstRange, TSecondRange&& secondRange, TMoreRanges&&... moreRanges) +{ + return chain(std::forward(firstRange), chain(std::forward(secondRange), std::forward(moreRanges)...)); } } // namespace mijin