forked from OctaForge/libostd
add complete input iterator type for any range
This commit is contained in:
parent
301dc1e607
commit
ef147c538c
|
@ -1,6 +1,7 @@
|
||||||
#include <ostd/range.hh>
|
#include <ostd/range.hh>
|
||||||
#include <ostd/io.hh>
|
#include <ostd/io.hh>
|
||||||
#include <ostd/algorithm.hh>
|
#include <ostd/algorithm.hh>
|
||||||
|
#include <ostd/vector.hh>
|
||||||
|
|
||||||
using namespace ostd;
|
using namespace ostd;
|
||||||
|
|
||||||
|
@ -66,4 +67,12 @@ int main() {
|
||||||
for (auto v: iter({ 5, 10, 15, 20 }).zip(iter({ 6, 11, 16, 21 }))) {
|
for (auto v: iter({ 5, 10, 15, 20 }).zip(iter({ 6, 11, 16, 21 }))) {
|
||||||
writeln(v.first, ", ", v.second);
|
writeln(v.first, ", ", v.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* insertion into containers with full_iterator */
|
||||||
|
writeln("vector range insert");
|
||||||
|
std::vector<int> foo = { 5, 10, 35, 40 };
|
||||||
|
writeln("before insert: ", foo);
|
||||||
|
auto r = range(15, 35, 5);
|
||||||
|
foo.insert(foo.cbegin() + 2, r.iter_begin(), r.iter_end());
|
||||||
|
writeln("after insert: ", foo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace ostd {
|
namespace ostd {
|
||||||
|
|
||||||
|
@ -619,7 +620,49 @@ namespace detail {
|
||||||
return !p_range.empty();
|
return !p_range.empty();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::decay_t<T> p_range;
|
T p_range;
|
||||||
|
};
|
||||||
|
|
||||||
|
// complete range iterator
|
||||||
|
template<typename T>
|
||||||
|
struct full_range_iterator {
|
||||||
|
using iterator_category = std::input_iterator_tag;
|
||||||
|
using value_type = range_value_t<T>;
|
||||||
|
using reference = range_reference_t<T>;
|
||||||
|
using pointer = value_type *;
|
||||||
|
using difference_type = std::make_signed_t<range_size_t<T>>;
|
||||||
|
|
||||||
|
full_range_iterator(): p_range(std::nullopt) {}
|
||||||
|
full_range_iterator(T const &range): p_range(range) {}
|
||||||
|
|
||||||
|
bool operator==(full_range_iterator const &v) const {
|
||||||
|
if (!p_range) {
|
||||||
|
if (v.p_range) {
|
||||||
|
return (*v.p_range).empty();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (*p_range).empty();
|
||||||
|
}
|
||||||
|
bool operator!=(full_range_iterator const &v) const {
|
||||||
|
return !((*this) == v);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference operator*() const {
|
||||||
|
return (*p_range).front();
|
||||||
|
}
|
||||||
|
|
||||||
|
full_range_iterator &operator++() {
|
||||||
|
p_range.value().pop_front();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
full_range_iterator operator++(int) {
|
||||||
|
full_range_iterator ret{p_range.value()};
|
||||||
|
(*p_range).pop_front();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::optional<T> p_range;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,6 +767,23 @@ inline range_size_t<IR> range_pop_back_n(IR &range, range_size_t<IR> n) {
|
||||||
*/
|
*/
|
||||||
template<typename B>
|
template<typename B>
|
||||||
struct input_range {
|
struct input_range {
|
||||||
|
/** @brief A complete input iterator type for the range.
|
||||||
|
*
|
||||||
|
* This is a complete iterator type that you can create with
|
||||||
|
* iter_begin(). This iterator can only be used to represent
|
||||||
|
* the full range sequence - i.e. from the beginning to the
|
||||||
|
* end of the range, with the end always being iter_end().
|
||||||
|
*
|
||||||
|
* Using an incremented version of iter_begin() as an ending is
|
||||||
|
* undefined as the ending iterator is not used by itself, this
|
||||||
|
* is why it's an input iterator type (if the function this is
|
||||||
|
* used with tried to use a temporary copy of the iterator as
|
||||||
|
* an end, it'd result in incorrect behavior). Thus, this is
|
||||||
|
* mostly meant to insert ranges into data structures that
|
||||||
|
* take input iterators in their insertion methods.
|
||||||
|
*/
|
||||||
|
using full_iterator = detail::full_range_iterator<B>;
|
||||||
|
|
||||||
/** @brief Creates a very simple iterator for range-based for loop.
|
/** @brief Creates a very simple iterator for range-based for loop.
|
||||||
*
|
*
|
||||||
* Thanks to this, you can use the range-based for loop with ranges
|
* Thanks to this, you can use the range-based for loop with ranges
|
||||||
|
@ -740,6 +800,16 @@ struct input_range {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Constructs a full_iterator for the range. */
|
||||||
|
full_iterator iter_begin() const {
|
||||||
|
return full_iterator{*static_cast<B const *>(this)};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Constructs a full_iterator end. */
|
||||||
|
full_iterator iter_end() const {
|
||||||
|
return full_iterator{};
|
||||||
|
}
|
||||||
|
|
||||||
/** @brief Creates a copy of the range.
|
/** @brief Creates a copy of the range.
|
||||||
*
|
*
|
||||||
* This is just like copy-constructing the range.
|
* This is just like copy-constructing the range.
|
||||||
|
|
Loading…
Reference in a new issue