1 Star 2 Fork 1

魏兆华/StudyCpp

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
conduit.cpp 8.07 KB
一键复制 编辑 原始数据 按行查看 历史
魏兆华 提交于 2022-09-13 23:09 . small correction
//Rewrite from https://github.com/LoopPerfect/conduit
//Test successfully on VS2009 16.11.2
#include <coroutine>
#include <iostream>
#include <optional>
#include <vector>
namespace conduit
{
template<typename R>
concept sequence = requires(R & r) { r.begin(); r.end(); };
template<std::movable T>
class seq
{
public:
struct promise_type
{
seq<T> get_return_object() { return { Handle::from_promise(*this) }; }
static std::suspend_always initial_suspend() noexcept { return {}; }
static std::suspend_always final_suspend() noexcept { return {}; }
static void return_void() noexcept {}
std::suspend_always yield_value(T value) noexcept
{
current_value = std::move(value);
return {};
}
//void await_transform() = delete;
[[noreturn]] static void unhandled_exception() { throw; }
std::optional<T> current_value;
};
using Handle = std::coroutine_handle<promise_type>;
class iterator
{
public:
void operator++() { m_coroutine.resume(); }
const T& operator*() const { return *m_coroutine.promise().current_value; }
bool operator==(std::default_sentinel_t) const { return !m_coroutine || m_coroutine.done(); }
explicit iterator(const Handle coroutine) : m_coroutine{ coroutine } {}
private:
Handle m_coroutine;
};
explicit seq(const Handle coroutine) : m_coroutine{ coroutine } {}
seq() = default;
~seq() { if (m_coroutine) m_coroutine.destroy(); }
seq(const seq&) = delete;
seq(seq&& other) noexcept : m_coroutine{ other.m_coroutine } { other.m_coroutine = {}; }
seq& operator=(const seq&) = delete;
seq& operator=(seq&& other) noexcept
{
if (this != &other) {
if (m_coroutine)
m_coroutine.destroy();
m_coroutine = other.m_coroutine;
other.m_coroutine = {};
}
return *this;
}
iterator begin()
{
if (m_coroutine)
m_coroutine.resume();
return iterator{ m_coroutine };
}
std::default_sentinel_t end() { return {}; }
private:
Handle m_coroutine;
};
template<typename T>
T id(T const& x) { return x; }
template<typename T>
auto first(T&& xs) -> decltype(id(*xs.begin())) { return *xs.begin(); }
namespace detail
{
template<typename B, typename E, typename S>
auto range(B b, E e, S step) -> seq<B> { while (b < e) { co_yield b; b += step; } };
template<typename B, typename E>
auto range(B b, E e) -> seq<B> { while (b < e) { co_yield b; ++b; } };
template<typename T = unsigned long>
auto range(T b = 0) -> seq<T> { while (true) { co_yield b; ++b; } };
auto find = [](sequence auto xs, auto f) -> seq<decltype(first(xs))> {
for (auto x : xs) {
if (f(x)) {
co_yield x;
break;
}
}
};
template<sequence Xs>
auto take(Xs xs, unsigned n) -> seq<decltype(first(xs))>
{
if (!n) co_return;
for (auto x : xs) {
co_yield x;
if (--n == 0)
break;
}
};
auto map = [](sequence auto xs, auto f) -> seq<decltype(id(f(first(xs))))> {
for (auto x : xs)
co_yield f(x);
};
auto flatMap = [](sequence auto xs, auto f) -> seq<decltype(first(f(first(xs))))> {
for (auto x : xs) //每个元素
for (auto&& y : f(x)) //调用函数之后生成一个序列
co_yield std::move(y); //再逐个yield
};
template<sequence Xs, typename Task>
auto forEach(Xs xs, Task task) -> seq<decltype(first(xs))>
{
for (auto x : xs) {
task(x);
co_yield x;
}
};
template<sequence Xs, typename Xsf>
auto orElse(Xs xs, Xsf xsf) -> seq<decltype(first(xs))>
{
bool hasElements = false;
for (auto x : xs) {
hasElements = true;
co_yield x;
}
if (!hasElements) {
for (auto x : xsf())
co_yield x;
}
}
template<sequence Xs, sequence Ys>
auto concat(Xs xs, Ys ys) -> seq<decltype(first(xs))>
{
for (auto x : xs)
co_yield x;
for (auto x : ys)
co_yield x;
}
auto all = [](auto...c) { return (c && ... && true); };
auto rangeUndone = [](auto& g) { auto& [_, b, e] = g; return b != e; };
template<typename F, typename...Xs>
auto zip(F f, Xs...xs) -> seq<decltype(f(*std::get<1>(xs)...))>
{
while (all(rangeUndone(xs)...)) {
co_yield f(*std::get<1>(xs)...);
(++std::get<1>(xs), ..., 0);
}
}
template<typename F, sequence...Xs>
auto zip(F&& f, Xs&&...xs)
{
return zip(std::forward<decltype(f)>(f),
std::tuple<decltype(id(xs)), decltype(id(xs.begin())), decltype(id(xs.end()))> { std::move(xs), xs.begin(), xs.end() }...
);
}
} //namespace detail
auto range = [](auto...args) { return detail::range(args...); };
auto count = [](unsigned long start = 0) {
return [start](sequence auto xs) -> seq<unsigned long> {
unsigned long i = start;
for (auto x : xs) {
(void)x;
co_yield i;
++i;
}
};
};
template<typename...Xs>
auto just(Xs...xs)
{
if constexpr (sizeof...(xs) > 0) {
using T = std::common_type_t<decltype(xs)...>;
return [=]() -> seq<T> {
T data[] = { (T)xs... };
for (auto x : data)
co_yield x;
};
} else {
return []() -> seq<int> { co_return; };
}
}
auto find = [](auto f) {
return [f](sequence auto&& xs) {
return detail::find(std::forward<decltype(xs)>(xs), f);
};
};
auto take = [](unsigned n) {
return [n](sequence auto&& xs) {
return detail::take(std::forward<decltype(xs)>(xs), n);
};
};
auto startsWith = [](auto...xsf) {
return [=](sequence auto&& ys) mutable {
return detail::concat(xsf()..., std::forward<decltype(ys)>(ys));
};
};
auto map = [](auto f) {
return [f](sequence auto&& xs) {
return detail::map(std::forward<decltype(xs)>(xs), f);
};
};
auto flatMap = [](auto&& f) {
return [f](sequence auto&& xs) {
return detail::flatMap(std::forward<decltype(xs)>(xs), f);
};
};
auto forEach = [](auto task) {
return [task](sequence auto&& xs) -> seq<decltype(first(xs))> {
return detail::forEach(std::forward<decltype(xs)>(xs), task);
};
};
auto orElse = [](auto xsf) {
return [xsf](sequence auto&& xs) {
return detail::orElse(std::forward<decltype(xs)>(xs), xsf);
};
};
auto concat = [](sequence auto&&...xs) {
return detail::concat(std::forward<decltype(xs)>(xs)...);
};
auto zip = [](auto&& f, sequence auto&&...xs) {
return detail::zip(std::forward<decltype(f)>(f), std::forward<decltype(xs)>(xs)...);
};
auto zipWith = [](auto g, auto f) {
return [g, f](sequence auto&& ys) {
return zip(f, g(), std::forward<decltype(ys)>(ys));
};
};
template <sequence Xs, typename F>
auto operator >> (Xs&& xs, F&& f)
{
return f(std::forward<decltype(xs)>(xs)); //xs只要是容器就可以,所以后面vector可用
}
} //namespace conduit
using namespace conduit;
int main()
{
auto primes = range() //seq<ulong>: 0, 1, 2, 3...
>> map([](auto i) {return (3 + i * 2); }) //3,5,7,9...
>> flatMap([primeVector = std::vector<int>()](auto c) mutable { //确保向量可修改
return primeVector //已经找到的质数,是一个vector(生存期同 flatMap),可以用>>
>> take(primeVector.size()) //逐一拿出来尝试
>> find([c](auto p) { return c % p == 0; }) //找到一个就 yield & break
>> count() //能整除就 yield 其序号(默认返回零)
>> orElse(just(c)) //若左侧没有元素,则逐一 yield 右侧。因此 yield 要么 0,要么 c
>> find([](auto x) { return x; }) //再排除掉零,剩下要么 c,要么空
>> forEach([&](auto p) { primeVector.push_back(p); }); //非空则加进向量
})
>> startsWith(just(2ul))
>> take(10)
>> zipWith(range, [](auto x, auto y) { return std::tuple{ x, y }; }); //打包其实没必要,只为演示
for (auto& [i, n] : primes)
std::cout << n << std::endl;
return 0;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/sunwaywei/study-cpp.git
git@gitee.com:sunwaywei/study-cpp.git
sunwaywei
study-cpp
StudyCpp
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385