Added replace() and chain() functions for generating replacing and chaining iterables. Also added a proxy type to allow combining different iteratables.
This commit is contained in:
parent
04520a5d35
commit
ef5d78e1b1
@ -5,9 +5,46 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace mijin
|
namespace mijin
|
||||||
{
|
{
|
||||||
|
struct RangeAdapter {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct RangeRef
|
||||||
|
{
|
||||||
|
T& range;
|
||||||
|
|
||||||
|
decltype(auto) begin() const
|
||||||
|
{
|
||||||
|
return std::begin(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
decltype(auto) end() const
|
||||||
|
{
|
||||||
|
return std::end(range);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<typename T>
|
||||||
|
concept RangeAdapterType = std::is_base_of_v<RangeAdapter, T>;
|
||||||
|
|
||||||
|
template<RangeAdapterType T>
|
||||||
|
struct RangeRef<T>
|
||||||
|
{
|
||||||
|
T range;
|
||||||
|
|
||||||
|
decltype(auto) begin() const
|
||||||
|
{
|
||||||
|
return range.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
decltype(auto) end() const
|
||||||
|
{
|
||||||
|
return range.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename TIdx, typename TIterator>
|
template<typename TIdx, typename TIterator>
|
||||||
struct EnumeratingIterator
|
struct EnumeratingIterator
|
||||||
{
|
{
|
||||||
@ -66,9 +103,9 @@ template<typename TIdx, typename TIterator>
|
|||||||
EnumeratingIterator(TIdx, TIterator) -> EnumeratingIterator<TIdx, TIterator>;
|
EnumeratingIterator(TIdx, TIterator) -> EnumeratingIterator<TIdx, TIterator>;
|
||||||
|
|
||||||
template<typename TIdx, typename TIterable>
|
template<typename TIdx, typename TIterable>
|
||||||
struct Enumeratable
|
struct Enumeratable : RangeAdapter
|
||||||
{
|
{
|
||||||
TIterable& base;
|
RangeRef<TIterable> base;
|
||||||
|
|
||||||
auto begin() const noexcept
|
auto begin() const noexcept
|
||||||
{
|
{
|
||||||
@ -82,9 +119,232 @@ struct Enumeratable
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename TIdx = std::size_t, typename TIterable>
|
template<typename TIdx = std::size_t, typename TIterable>
|
||||||
Enumeratable<TIdx, TIterable> enumerate(TIterable& iterable)
|
Enumeratable<TIdx, TIterable> enumerate(TIterable&& iterable)
|
||||||
{
|
{
|
||||||
return {iterable};
|
return {.base = {std::forward<TIterable>(iterable)}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TIterator>
|
||||||
|
struct ReplacingIterator
|
||||||
|
{
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using value_type = typename std::iterator_traits<TIterator>::value_type;
|
||||||
|
using pointer = std::add_const_t<value_type>*;
|
||||||
|
using reference = std::add_const_t<value_type>&;
|
||||||
|
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<typename TIterable>
|
||||||
|
struct ReplacingRange : RangeAdapter
|
||||||
|
{
|
||||||
|
using value_type = typename std::iterator_traits<decltype(std::begin(std::declval<TIterable>()))>::value_type;
|
||||||
|
|
||||||
|
RangeRef<TIterable> 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<typename TIterable>
|
||||||
|
auto replace(
|
||||||
|
TIterable&& iterable,
|
||||||
|
typename std::iterator_traits<decltype(std::begin(std::declval<TIterable>()))>::value_type what,
|
||||||
|
typename std::iterator_traits<decltype(std::begin(std::declval<TIterable>()))>::value_type with)
|
||||||
|
{
|
||||||
|
return ReplacingRange<TIterable>{
|
||||||
|
.base = {std::forward<TIterable>(iterable)},
|
||||||
|
.what = std::move(what),
|
||||||
|
.with = std::move(with)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFirstIterator, typename TSecondIterator>
|
||||||
|
struct ChainingIterator
|
||||||
|
{
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using value_type = typename std::iterator_traits<TFirstIterator>::value_type;
|
||||||
|
using pointer = std::add_const_t<value_type>*;
|
||||||
|
using reference = std::add_const_t<value_type>&;
|
||||||
|
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<typename TFirstRange, typename TSecondRange>
|
||||||
|
struct ChainedRange : RangeAdapter
|
||||||
|
{
|
||||||
|
using value_type = typename std::iterator_traits<decltype(std::begin(std::declval<TFirstRange>()))>::value_type;
|
||||||
|
|
||||||
|
RangeRef<TFirstRange> first;
|
||||||
|
RangeRef<TSecondRange> 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<typename TFirstRange, typename TSecondRange>
|
||||||
|
auto chain(TFirstRange&& firstRange, TSecondRange&& secondRange)
|
||||||
|
{
|
||||||
|
return ChainedRange<TFirstRange, TSecondRange>{
|
||||||
|
.first = {std::forward<TFirstRange>(firstRange)},
|
||||||
|
.second = {std::forward<TSecondRange>(secondRange)}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFirstRange, typename TSecondRange, typename... TMoreRanges>
|
||||||
|
auto chain(TFirstRange&& firstRange, TSecondRange&& secondRange, TMoreRanges&&... moreRanges)
|
||||||
|
{
|
||||||
|
return chain(std::forward<TFirstRange>(firstRange), chain(std::forward<TSecondRange>(secondRange), std::forward<TMoreRanges>(moreRanges)...));
|
||||||
}
|
}
|
||||||
} // namespace mijin
|
} // namespace mijin
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user