add ranges & fix filter
This commit is contained in:
parent
0ec206cade
commit
23b0a79200
8
libvmake/examples/empty_sequence.cpp
Normal file
8
libvmake/examples/empty_sequence.cpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include "../vmake.hpp"
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
vmake::output(cout, vmake::nothing<string>());
|
||||||
|
return 0;
|
||||||
|
}
|
14
libvmake/examples/filtering.cpp
Normal file
14
libvmake/examples/filtering.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include "../vmake.hpp"
|
||||||
|
#include <vector>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
vmake::output(cout, " ", vmake::filter(vmake::range(1, 10), [](int x) {
|
||||||
|
return x % 2 == 0;
|
||||||
|
}));
|
||||||
|
cout << endl;
|
||||||
|
vmake::output(cout, " ", vmake::take(vmake::filter(vmake::iota(1), [](int x) {
|
||||||
|
return x <= 5;
|
||||||
|
}), 5));
|
||||||
|
return 0;
|
||||||
|
}
|
@ -7,21 +7,106 @@
|
|||||||
namespace vmake {
|
namespace vmake {
|
||||||
|
|
||||||
struct sequence_terminated_error : std::exception {
|
struct sequence_terminated_error : std::exception {
|
||||||
// TODO
|
virtual const char *what() const noexcept override final {
|
||||||
|
return "iterating on a terminated sequence.";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct iota_sequence {
|
||||||
|
using result = T;
|
||||||
|
|
||||||
|
T start;
|
||||||
|
iota_sequence(const T& start) : start(start) {}
|
||||||
|
|
||||||
|
bool is_terminated() const noexcept {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator()() {
|
||||||
|
return start++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ranged_sequence {
|
||||||
|
using result = T;
|
||||||
|
|
||||||
|
T start, end;
|
||||||
|
ranged_sequence(const T& start, const T& end) : start(start), end(end) {}
|
||||||
|
|
||||||
|
bool is_terminated() const noexcept {
|
||||||
|
return start == end;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator()() {
|
||||||
|
if (start == end) throw sequence_terminated_error();
|
||||||
|
return start++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ranged_step_sequence {
|
||||||
|
using result = T;
|
||||||
|
|
||||||
|
T start, end, step;
|
||||||
|
ranged_step_sequence(const T& start, const T& end, const T& step) : start(start), end(end), step(step) {}
|
||||||
|
|
||||||
|
bool is_terminated() const noexcept {
|
||||||
|
return start == end;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator()() {
|
||||||
|
if (start == end) throw sequence_terminated_error();
|
||||||
|
T res = start;
|
||||||
|
start += step;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
template<typename Val>
|
||||||
|
inline auto iota(const Val &start) {
|
||||||
|
return details::iota_sequence<Val>(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Val>
|
||||||
|
inline auto range(const Val &start, const Val &end) {
|
||||||
|
return details::ranged_sequence<Val>(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Val>
|
||||||
|
inline auto range(const Val &start, const Val &end, const Val &step) {
|
||||||
|
return details::ranged_step_sequence<Val>(start, end, step);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct empty_sequence {
|
||||||
|
using result = T;
|
||||||
|
|
||||||
|
bool is_terminated() const noexcept {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator()() {
|
||||||
|
throw sequence_terminated_error();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename ContIt>
|
template<typename ContIt>
|
||||||
struct extractor {
|
struct extractor {
|
||||||
using core = ContIt;
|
|
||||||
using result = typename std::remove_reference<decltype(*std::declval<ContIt>())>::type;
|
using result = typename std::remove_reference<decltype(*std::declval<ContIt>())>::type;
|
||||||
|
|
||||||
ContIt cur, end;
|
ContIt cur, end;
|
||||||
|
|
||||||
extractor(const ContIt &begin, const ContIt &end) : cur(begin), end(end) {}
|
extractor(const ContIt &begin, const ContIt &end) : cur(begin), end(end) {}
|
||||||
|
|
||||||
bool is_terminated() const {
|
bool is_terminated() const noexcept {
|
||||||
return cur == end;
|
return cur == end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +118,6 @@ struct extractor {
|
|||||||
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
struct generator {
|
struct generator {
|
||||||
using core = Func;
|
|
||||||
using result = typename std::result_of<Func()>::type;
|
using result = typename std::result_of<Func()>::type;
|
||||||
|
|
||||||
Func g;
|
Func g;
|
||||||
@ -46,7 +130,7 @@ struct generator {
|
|||||||
generator(generator<Func> &&y) = default;
|
generator(generator<Func> &&y) = default;
|
||||||
generator(const generator<Func> &y) = default;
|
generator(const generator<Func> &y) = default;
|
||||||
|
|
||||||
bool is_terminated() const {
|
bool is_terminated() const noexcept {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +150,7 @@ struct limitor {
|
|||||||
limitor(limitor<Gen> &&g) = default;
|
limitor(limitor<Gen> &&g) = default;
|
||||||
limitor(const limitor<Gen> &g) = default;
|
limitor(const limitor<Gen> &g) = default;
|
||||||
|
|
||||||
bool is_terminated() const {
|
bool is_terminated() const noexcept {
|
||||||
return lim <= 0;
|
return lim <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +162,11 @@ struct limitor {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline auto nothing() {
|
||||||
|
return details::empty_sequence<T>();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Gen>
|
template<typename Gen>
|
||||||
inline auto take(Gen &&g, size_t lim) {
|
inline auto take(Gen &&g, size_t lim) {
|
||||||
return details::limitor<typename std::decay<decltype(g)>::type>(std::move(g), lim);
|
return details::limitor<typename std::decay<decltype(g)>::type>(std::move(g), lim);
|
||||||
@ -90,7 +179,7 @@ inline auto make_generator(Args ...args) {
|
|||||||
|
|
||||||
namespace rng {
|
namespace rng {
|
||||||
|
|
||||||
template<typename Engine>
|
template<typename Engine = std::default_random_engine>
|
||||||
inline auto common() {
|
inline auto common() {
|
||||||
// NOTE: MinGW GCC older than 9.2 have a fixed random_device
|
// NOTE: MinGW GCC older than 9.2 have a fixed random_device
|
||||||
return make_generator<Engine>(std::random_device{}());
|
return make_generator<Engine>(std::random_device{}());
|
||||||
@ -101,10 +190,12 @@ inline auto common(Seed seed) {
|
|||||||
return make_generator<Engine>(seed);
|
return make_generator<Engine>(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cstyle_rng {
|
namespace details {
|
||||||
using result = int;
|
|
||||||
|
|
||||||
bool is_terminated() const {
|
struct cstyle_rng {
|
||||||
|
using result = decltype(std::rand());
|
||||||
|
|
||||||
|
bool is_terminated() const noexcept {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,16 +204,18 @@ struct cstyle_rng {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
inline auto cstyle() {
|
inline auto cstyle() {
|
||||||
std::srand(time(0));
|
std::srand(time(0));
|
||||||
std::rand();
|
std::rand();
|
||||||
return cstyle_rng();
|
return details::cstyle_rng();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto cstyle(int seed) {
|
inline auto cstyle(int seed) {
|
||||||
std::srand(seed);
|
std::srand(seed);
|
||||||
std::rand();
|
std::rand();
|
||||||
return cstyle_rng();
|
return details::cstyle_rng();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -162,7 +255,7 @@ struct concator {
|
|||||||
concator(const concator<Gen1, Gen2> &c) = default;
|
concator(const concator<Gen1, Gen2> &c) = default;
|
||||||
// concator<Gen1, Gen2>& operator=(concator<Gen1, Gen2> &&c) = default;
|
// concator<Gen1, Gen2>& operator=(concator<Gen1, Gen2> &&c) = default;
|
||||||
|
|
||||||
bool is_terminated() const {
|
bool is_terminated() const noexcept {
|
||||||
return g1.is_terminated() && g2.is_terminated();
|
return g1.is_terminated() && g2.is_terminated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +266,7 @@ struct concator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename Gen1, typename Gen2>
|
template<typename Gen1, typename Gen2>
|
||||||
inline auto concat(Gen1 &&x, Gen2 &&y) {
|
inline constexpr auto concat(Gen1 &&x, Gen2 &&y) noexcept {
|
||||||
return concator<Gen1, Gen2>(std::move(x), std::move(y));
|
return concator<Gen1, Gen2>(std::move(x), std::move(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +283,7 @@ struct transformer {
|
|||||||
transformer(const transformer<Gen, Func> &c) = default;
|
transformer(const transformer<Gen, Func> &c) = default;
|
||||||
// transformer& operator=(transformer<Gen, Func> &&c) = default;
|
// transformer& operator=(transformer<Gen, Func> &&c) = default;
|
||||||
|
|
||||||
bool is_terminated() const {
|
bool is_terminated() const noexcept {
|
||||||
return g.is_terminated();
|
return g.is_terminated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +304,7 @@ inline auto output(OutputStream& out, const char *delim, Gen &&g) {
|
|||||||
|
|
||||||
template<typename OutputStream, typename Gen>
|
template<typename OutputStream, typename Gen>
|
||||||
inline auto output(OutputStream& out, Gen &&g) {
|
inline auto output(OutputStream& out, Gen &&g) {
|
||||||
return copy(std::ostream_iterator<typename std::decay<Gen>::type::result>(out), g);
|
return copy(std::ostream_iterator<typename std::decay<Gen>::type::result>(out), std::move(g));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename OutputStream, typename Gen>
|
template<typename OutputStream, typename Gen>
|
||||||
@ -225,8 +318,8 @@ inline auto output_n(OutputStream& out, size_t n, Gen &&g) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
inline auto generate(Func &&f) {
|
inline constexpr auto generate(Func &&f) {
|
||||||
return details::generator<Func>(std::move(f));
|
return details::generator<Func>(std::forward<Func>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace polyfill {
|
namespace polyfill {
|
||||||
@ -237,7 +330,7 @@ struct as_const_reference_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline auto as_const_reference(typename as_const_reference_t<T>::type x) {
|
inline constexpr auto as_const_reference(typename as_const_reference_t<T>::type x) noexcept {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,30 +347,35 @@ struct filteror {
|
|||||||
filteror(filteror<Gen, Pred> &&) = default;
|
filteror(filteror<Gen, Pred> &&) = default;
|
||||||
filteror(const filteror<Gen, Pred> &) = default;
|
filteror(const filteror<Gen, Pred> &) = default;
|
||||||
|
|
||||||
Gen g;
|
mutable Gen g;
|
||||||
Pred p;
|
Pred p;
|
||||||
polyfill::optional<result> preview;
|
mutable polyfill::optional<result> preview;
|
||||||
|
|
||||||
filteror(Gen &&g, Pred &&p) : g(std::forward<Gen>(g)), p(std::forward<Pred>(p)), preview() {
|
filteror(Gen &&g, Pred &&p) : g(std::forward<Gen>(g)), p(std::forward<Pred>(p)), preview() {
|
||||||
_find_next();
|
_find_next();
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_terminated() const {
|
bool is_terminated() const noexcept {
|
||||||
return g.is_terminated() && !preview.has_value();
|
if (g.is_terminated() && !preview.has_value()) return true;
|
||||||
|
if (!preview.has_value()) _find_next();
|
||||||
|
return !preview.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator()() {
|
auto operator()() {
|
||||||
if (is_terminated()) throw sequence_terminated_error();
|
if (is_terminated()) throw sequence_terminated_error();
|
||||||
result res = std::move(*preview);
|
result res = std::move(*preview);
|
||||||
_find_next();
|
preview.reset();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _find_next() {
|
void _find_next() const {
|
||||||
preview.reset();
|
preview.reset();
|
||||||
do {
|
do {
|
||||||
if (g.is_terminated()) return;
|
if (g.is_terminated()) {
|
||||||
|
preview.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
preview.emplace(std::move(g()));
|
preview.emplace(std::move(g()));
|
||||||
} while (!p(polyfill::as_const_reference<result>(*preview)));
|
} while (!p(polyfill::as_const_reference<result>(*preview)));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user