Commit a855776b authored by Kirk Shoop's avatar Kirk Shoop Committed by Facebook Github Bot

add new operators to single header (#18)

fbshipit-source-id: 1df9cc44331327b62fb7e20f22f8f512fe4e6ecd
parent 3e05ecc2
...@@ -18,7 +18,7 @@ function(BuildSingleHeader HeaderName) ...@@ -18,7 +18,7 @@ function(BuildSingleHeader HeaderName)
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/include/${HeaderName}.h "${incls}") file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/include/${HeaderName}.h "${incls}")
endfunction() endfunction()
set(header_files set(header_files
# keep in inclusion order # keep in inclusion order
"${CMAKE_CURRENT_SOURCE_DIR}/external/meta/include/meta/meta_fwd.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/external/meta/include/meta/meta_fwd.hpp"
...@@ -45,14 +45,18 @@ set(header_files ...@@ -45,14 +45,18 @@ set(header_files
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/flow_single_deferred.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/flow_single_deferred.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/trampoline.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/trampoline.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/new_thread.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/new_thread.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/empty.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/extension_operators.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/extension_operators.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/submit.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/subject.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/empty.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/just.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/just.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/defer.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/on.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/on.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/submit.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/tap.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/tap.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/transform.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/transform.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/via.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/via.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/request_via.h"
"${CMAKE_CURRENT_SOURCE_DIR}/include/pushmi/o/share.h"
) )
BuildSingleHeader("pushmi" ${header_files}) BuildSingleHeader("pushmi" ${header_files})
\ No newline at end of file
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <future> #include <future>
#include <tuple> #include <tuple>
#include <deque> #include <deque>
#include <vector>
#if __cpp_lib_optional >= 201606 #if __cpp_lib_optional >= 201606
#include <optional> #include <optional>
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <future> #include <future>
#include <tuple> #include <tuple>
#include <deque> #include <deque>
#include <vector>
#if __cpp_lib_optional >= 201606 #if __cpp_lib_optional >= 201606
#include <optional> #include <optional>
...@@ -8311,43 +8312,6 @@ inline auto new_thread() { ...@@ -8311,43 +8312,6 @@ inline auto new_thread() {
// This source code is licensed under the MIT license found in the // This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree. // LICENSE file in the root directory of this source tree.
//#include <meta/meta.hpp>
//#include "../deferred.h"
//#include "../single_deferred.h"
//#include "../detail/functional.h"
namespace pushmi {
namespace operators {
template <class V>
auto empty() {
return make_single_deferred(
constrain(lazy::SingleReceiver<_1, V>, [](auto out) mutable {
::pushmi::set_done(out);
})
);
}
inline auto empty() {
return make_deferred(
constrain(lazy::NoneReceiver<_1>, [](auto out) mutable {
::pushmi::set_done(out);
})
);
}
} // namespace operators
} // namespace pushmi
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
//#pragma once
// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//#include <tuple> //#include <tuple>
//#include "../piping.h" //#include "../piping.h"
//#include "../boosters.h" //#include "../boosters.h"
...@@ -8624,83 +8588,487 @@ PUSHMI_INLINE_VAR constexpr detail::now_fn top{}; ...@@ -8624,83 +8588,487 @@ PUSHMI_INLINE_VAR constexpr detail::now_fn top{};
// This source code is licensed under the MIT license found in the // This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree. // LICENSE file in the root directory of this source tree.
//#include "../single_deferred.h" //#include <functional>
//#include "submit.h" //#include "../time_single_deferred.h"
//#include "extension_operators.h" //#include "../boosters.h"
namespace pushmi {
namespace operators {
PUSHMI_TEMPLATE(class V)
(requires SemiMovable<V>)
auto just(V v) {
return make_single_deferred(
constrain(lazy::SingleReceiver<_1, V>,
[v = std::move(v)](auto out) mutable {
::pushmi::set_value(out, std::move(v));
}
)
);
}
} // namespace operators
} // namespace pushmi
//#pragma once
// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//#include "../piping.h"
//#include "../executor.h"
//#include "extension_operators.h" //#include "extension_operators.h"
//#include "../trampoline.h"
//#include "../detail/opt.h"
//#include "../detail/if_constexpr.h"
namespace pushmi { namespace pushmi {
namespace detail { namespace detail {
namespace submit_detail {
template <PUSHMI_TYPE_CONSTRAINT(Sender) In, class ...AN>
using receiver_type_t =
pushmi::invoke_result_t<
pushmi::detail::make_receiver<property_set_index_t<properties_t<In>, is_silent<>>>,
AN...>;
struct on_fn { PUSHMI_CONCEPT_DEF(
PUSHMI_TEMPLATE(class ExecutorFactory) template (class In, class ... AN)
(requires Invocable<ExecutorFactory&>) (concept AutoSenderTo)(In, AN...),
auto operator()(ExecutorFactory ef) const { SenderTo<In, receiver_type_t<In, AN...>>
return constrain(lazy::Sender<_1>, [ef = std::move(ef)](auto in) { );
using In = decltype(in); PUSHMI_CONCEPT_DEF(
return ::pushmi::detail::deferred_from<In, single<>>( template (class In, class ... AN)
std::move(in), (concept AutoTimeSenderTo)(In, AN...),
::pushmi::detail::submit_transform_out<In>( TimeSenderTo<In, receiver_type_t<In, AN...>>
constrain(lazy::SenderTo<In, _2>, [ef](In& in, auto out) { );
auto exec = ef(); } // namespace submit_detail
::pushmi::submit(exec, ::pushmi::now(exec),
::pushmi::make_single([in = in, out = std::move(out)](auto) mutable { struct submit_fn {
::pushmi::submit(in, std::move(out)); private:
}) // TODO - only move, move-only types..
); // if out can be copied, then submit can be called multiple
}), // times..
constrain(lazy::TimeSenderTo<In, _3>, [ef](In& in, auto at, auto out) { template <class... AN>
auto exec = ef(); struct fn {
::pushmi::submit(exec, at, std::tuple<AN...> args_;
::pushmi::on_value([in = in, at, out = std::move(out)](auto) mutable { PUSHMI_TEMPLATE(class In)
::pushmi::submit(in, at, std::move(out)); (requires submit_detail::AutoSenderTo<In, AN...>)
}) In operator()(In in) {
); auto out{::pushmi::detail::out_from_fn<In>()(std::move(args_))};
}) ::pushmi::submit(in, std::move(out));
) return in;
); }
}); PUSHMI_TEMPLATE(class In)
(requires submit_detail::AutoTimeSenderTo<In, AN...>)
In operator()(In in) {
auto out{::pushmi::detail::out_from_fn<In>()(std::move(args_))};
::pushmi::submit(in, ::pushmi::now(in), std::move(out));
return in;
}
};
public:
template <class... AN>
auto operator()(AN&&... an) const {
return submit_fn::fn<AN...>{{(AN&&) an...}};
} }
}; };
} // namespace detail struct submit_at_fn {
private:
template <class TP, class...AN>
struct fn {
TP at_;
std::tuple<AN...> args_;
PUSHMI_TEMPLATE(class In)
(requires submit_detail::AutoTimeSenderTo<In, AN...>)
In operator()(In in) {
auto out{::pushmi::detail::out_from_fn<In>()(std::move(args_))};
::pushmi::submit(in, std::move(at_), std::move(out));
return in;
}
};
public:
PUSHMI_TEMPLATE(class TP, class...AN)
(requires Regular<TP>)
auto operator()(TP at, AN... an) const {
return submit_at_fn::fn<TP, AN...>{std::move(at), {(AN&&) an...}};
}
};
namespace operators { struct submit_after_fn {
private:
template <class D, class... AN>
struct fn {
D after_;
std::tuple<AN...> args_;
PUSHMI_TEMPLATE(class In)
(requires submit_detail::AutoTimeSenderTo<In, AN...>)
In operator()(In in) {
// TODO - only move, move-only types..
// if out can be copied, then submit can be called multiple
// times..
auto out{::pushmi::detail::out_from_fn<In>()(std::move(args_))};
auto at = ::pushmi::now(in) + std::move(after_);
::pushmi::submit(in, std::move(at), std::move(out));
return in;
}
};
public:
PUSHMI_TEMPLATE(class D, class...AN)
(requires Regular<D>)
auto operator()(D after, AN... an) const {
return submit_after_fn::fn<D, AN...>{std::move(after), {(AN&&) an...}};
}
};
PUSHMI_INLINE_VAR constexpr detail::on_fn on{}; struct blocking_submit_fn {
private:
// TODO - only move, move-only types..
// if out can be copied, then submit can be called multiple
// times..
template <class... AN>
struct fn {
std::tuple<AN...> args_;
} // namespace operators template <bool IsTimeSender, class In>
In impl_(In in) {
bool done = false;
std::condition_variable signaled;
auto out{::pushmi::detail::out_from_fn<In>()(
std::move(args_),
on_value(constrain(pushmi::lazy::Receiver<_1, is_single<>>,
[&](auto out, auto&& v) {
using V = remove_cvref_t<decltype(v)>;
PUSHMI_IF_CONSTEXPR( ((bool)Time<V>) (
// to keep the blocking semantics, make sure that the
// nested submits block here to prevent a spurious
// completion signal
auto nest = ::pushmi::nested_trampoline();
::pushmi::submit(nest, ::pushmi::now(nest), std::move(out));
) else (
::pushmi::set_value(out, id((V&&) v));
))
done = true;
signaled.notify_all();
}
)),
on_error(constrain(pushmi::lazy::NoneReceiver<_1, _2>,
[&](auto out, auto e) noexcept {
::pushmi::set_error(out, std::move(e));
done = true;
signaled.notify_all();
}
)),
on_done(constrain(pushmi::lazy::Receiver<_1>,
[&](auto out){
::pushmi::set_done(out);
done = true;
signaled.notify_all();
}
))
)};
PUSHMI_IF_CONSTEXPR( (IsTimeSender) (
id(::pushmi::submit)(in, id(::pushmi::now)(in), std::move(out));
) else (
id(::pushmi::submit)(in, std::move(out));
))
std::mutex lock;
std::unique_lock<std::mutex> guard{lock};
signaled.wait(guard, [&]{
return done;
});
return in;
}
PUSHMI_TEMPLATE(class In)
(requires submit_detail::AutoSenderTo<In, AN...>)
In operator()(In in) {
return this->impl_<false>(std::move(in));
}
PUSHMI_TEMPLATE(class In)
(requires submit_detail::AutoTimeSenderTo<In, AN...>)
In operator()(In in) {
return this->impl_<true>(std::move(in));
}
};
public:
template <class... AN>
auto operator()(AN... an) const {
return blocking_submit_fn::fn<AN...>{{(AN&&) an...}};
}
};
template <class T>
struct get_fn {
// TODO constrain this better
PUSHMI_TEMPLATE (class In)
(requires Sender<In>)
T operator()(In in) const {
pushmi::detail::opt<T> result_;
std::exception_ptr ep_;
auto out = make_single(
on_value([&](T t){ result_ = std::move(t); }),
on_error(
[&](auto e) noexcept { ep_ = std::make_exception_ptr(e); },
[&](std::exception_ptr ep) noexcept { ep_ = ep; })
);
using Out = decltype(out);
static_assert(SenderTo<In, Out, is_single<>> ||
TimeSenderTo<In, Out, is_single<>>,
"'In' does not deliver value compatible with 'T' to 'Out'");
blocking_submit_fn{}(std::move(out))(in);
if (!!ep_) { std::rethrow_exception(ep_); }
return std::move(*result_);
}
};
} // namespace detail
namespace operators {
PUSHMI_INLINE_VAR constexpr detail::submit_fn submit{};
PUSHMI_INLINE_VAR constexpr detail::submit_at_fn submit_at{};
PUSHMI_INLINE_VAR constexpr detail::submit_after_fn submit_after{};
PUSHMI_INLINE_VAR constexpr detail::blocking_submit_fn blocking_submit{};
template <class T>
PUSHMI_INLINE_VAR constexpr detail::get_fn<T> get{};
} // namespace operators
} // namespace pushmi
//#pragma once
// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//#include <vector>
//#include <pushmi/time_single_deferred.h>
namespace pushmi {
template<class... TN>
struct subject;
template<class T, class PS>
struct subject<T, PS> {
using properties = property_set_insert_t<property_set<is_sender<>, is_single<>>, PS>;
struct subject_shared {
bool done_ = false;
pushmi::detail::opt<T> t_;
std::exception_ptr ep_;
std::vector<any_single<T>> receivers_;
std::mutex lock_;
PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out>)
void submit(Out out) {
std::unique_lock<std::mutex> guard(lock_);
if (ep_) {::pushmi::set_error(out, ep_); return;}
if (!!t_) {::pushmi::set_value(out, (const T&)t_); return;}
if (done_) {::pushmi::set_done(out); return;}
receivers_.push_back(any_single<T>{out});
}
PUSHMI_TEMPLATE(class V)
(requires SemiMovable<V>)
void value(V&& v) {
std::unique_lock<std::mutex> guard(lock_);
t_ = detail::as_const(v);
for (auto& out : receivers_) {::pushmi::set_value(out, (V&&) v);}
receivers_.clear();
}
PUSHMI_TEMPLATE(class E)
(requires SemiMovable<E>)
void error(E e) noexcept {
std::unique_lock<std::mutex> guard(lock_);
ep_ = e;
for (auto& out : receivers_) {::pushmi::set_error(out, std::move(e));}
receivers_.clear();
}
void done() {
std::unique_lock<std::mutex> guard(lock_);
done_ = true;
for (auto& out : receivers_) {::pushmi::set_done(out);}
receivers_.clear();
}
};
// need a template overload of none/deferred and the rest that stores a 'ptr' with its own lifetime management
struct subject_receiver {
using properties = property_set_insert_t<property_set<is_receiver<>, is_single<>>, PS>;
std::shared_ptr<subject_shared> s;
PUSHMI_TEMPLATE(class V)
(requires SemiMovable<V>)
void value(V&& v) {
s->value((V&&) v);
}
PUSHMI_TEMPLATE(class E)
(requires SemiMovable<E>)
void error(E e) noexcept {
s->error(std::move(e));
}
void done() {
s->done();
}
};
std::shared_ptr<subject_shared> s = std::make_shared<subject_shared>();
PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out>)
void submit(Out out) {
s->submit(std::move(out));
}
auto receiver() {
return detail::out_from_fn<subject>{}(subject_receiver{s});
}
};
} // namespace pushmi
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
//#pragma once
// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//#include <meta/meta.hpp>
//#include "../deferred.h"
//#include "../single_deferred.h"
//#include "../detail/functional.h"
namespace pushmi {
namespace operators {
template <class V>
auto empty() {
return make_single_deferred(
constrain(lazy::SingleReceiver<_1, V>, [](auto out) mutable {
::pushmi::set_done(out);
})
);
}
inline auto empty() {
return make_deferred(
constrain(lazy::NoneReceiver<_1>, [](auto out) mutable {
::pushmi::set_done(out);
})
);
}
} // namespace operators
} // namespace pushmi
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
//#pragma once
// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//#include "../single_deferred.h"
//#include "submit.h"
//#include "extension_operators.h"
namespace pushmi {
namespace operators {
PUSHMI_TEMPLATE(class V)
(requires SemiMovable<V>)
auto just(V v) {
return make_single_deferred(
constrain(lazy::SingleReceiver<_1, V>,
[v = std::move(v)](auto out) mutable {
::pushmi::set_value(out, std::move(v));
}
)
);
}
} // namespace operators
} // namespace pushmi
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
//#pragma once
// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//#include "../single.h"
//#include "submit.h"
//#include "extension_operators.h"
#if __cpp_deduction_guides >= 201703
#define MAKE(x) x MAKE_
#define MAKE_(...) {__VA_ARGS__}
#else
#define MAKE(x) make_ ## x
#endif
namespace pushmi {
namespace operators {
PUSHMI_TEMPLATE(class F)
(requires Invocable<F>)
auto defer(F f) {
return MAKE(single_deferred)(
constrain(lazy::Receiver<_1>,
[f = std::move(f)](auto out) mutable {
auto sender = f();
PUSHMI_IF_CONSTEXPR( ((bool)TimeSender<decltype(sender)>) (
::pushmi::submit(sender, ::pushmi::now(id(sender)), std::move(out));
) else (
::pushmi::submit(sender, std::move(out));
));
}
)
);
}
} // namespace operators
} // namespace pushmi
//#pragma once
// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//#include "../piping.h"
//#include "../executor.h"
//#include "extension_operators.h"
namespace pushmi {
#if 0 namespace detail {
struct on_fn {
PUSHMI_TEMPLATE(class ExecutorFactory)
(requires Invocable<ExecutorFactory&>)
auto operator()(ExecutorFactory ef) const {
return constrain(lazy::Sender<_1>, [ef = std::move(ef)](auto in) {
using In = decltype(in);
return ::pushmi::detail::deferred_from<In, single<>>(
std::move(in),
::pushmi::detail::submit_transform_out<In>(
constrain(lazy::SenderTo<In, _2>, [ef](In& in, auto out) {
auto exec = ef();
::pushmi::submit(exec, ::pushmi::now(exec),
::pushmi::make_single([in = in, out = std::move(out)](auto) mutable {
::pushmi::submit(in, std::move(out));
})
);
}),
constrain(lazy::TimeSenderTo<In, _3>, [ef](In& in, auto at, auto out) {
auto exec = ef();
::pushmi::submit(exec, at,
::pushmi::on_value([in = in, at, out = std::move(out)](auto) mutable {
::pushmi::submit(in, at, std::move(out));
})
);
})
)
);
});
}
};
} // namespace detail
namespace operators {
PUSHMI_INLINE_VAR constexpr detail::on_fn on{};
} // namespace operators
#if 0
namespace detail { namespace detail {
template <class ExecutorFactory> template <class ExecutorFactory>
...@@ -8776,303 +9144,75 @@ class fsdon { ...@@ -8776,303 +9144,75 @@ class fsdon {
stopped_(std::make_shared<std::atomic_bool>(false)), stopped_(std::make_shared<std::atomic_bool>(false)),
out_(std::move(out)), out_(std::move(out)),
exec_(std::move(exec)), exec_(std::move(exec)),
upProxy_() {} upProxy_() {}
template <class T>
void value(T t) {
if (done_) {
return;
}
done_ = true;
out_.value(std::move(t));
}
template <class E>
void error(E e) {
if (done_) {
return;
}
done_ = true;
out_.error(std::move(e));
}
void stopping() {
if (done_) {
return;
}
done_ = true;
*stopped_ = true;
out_.stopping();
}
template <class Producer>
void starting(RefWrapper<Producer> up) {
upProxy_ =
producer_proxy<Producer>{std::move(up), stopped_, std::move(exec_)};
out_.starting(wrap_ref(upProxy_));
}
};
public:
start_on(executor_factory_type&& ef, in_type&& in)
: factory_(std::move(ef)), in_(std::move(in)) {}
template <class Out>
auto then(Out out) {
auto exec = factory_();
auto myout = out_on<Out, decltype(exec)>{std::move(out), exec};
exec | execute([in = in_, myout = std::move(myout)](auto) mutable {
in.then(std::move(myout));
});
}
};
public:
explicit fsdon(executor_factory_type&& ef) : factory_(std::move(ef)) {}
template <class In>
auto operator()(In in) {
return start_on<In>{std::move(factory_), std::move(in)};
}
};
} // namespace detail
namespace fsd {
template <class ExecutorFactory>
auto on(ExecutorFactory factory) {
return detail::fsdon<ExecutorFactory>{std::move(factory)};
}
} // namespace fsd
#endif
} // namespace pushmi
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
//#pragma once
// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//#include <functional>
//#include "../time_single_deferred.h"
//#include "../boosters.h"
//#include "extension_operators.h"
//#include "../trampoline.h"
//#include "../detail/opt.h"
//#include "../detail/if_constexpr.h"
namespace pushmi {
namespace detail {
namespace submit_detail {
template <PUSHMI_TYPE_CONSTRAINT(Sender) In, class ...AN>
using receiver_type_t =
pushmi::invoke_result_t<
pushmi::detail::make_receiver<property_set_index_t<properties_t<In>, is_silent<>>>,
AN...>;
PUSHMI_CONCEPT_DEF(
template (class In, class ... AN)
(concept AutoSenderTo)(In, AN...),
SenderTo<In, receiver_type_t<In, AN...>>
);
PUSHMI_CONCEPT_DEF(
template (class In, class ... AN)
(concept AutoTimeSenderTo)(In, AN...),
TimeSenderTo<In, receiver_type_t<In, AN...>>
);
} // namespace submit_detail
struct submit_fn {
private:
// TODO - only move, move-only types..
// if out can be copied, then submit can be called multiple
// times..
template <class... AN>
struct fn {
std::tuple<AN...> args_;
PUSHMI_TEMPLATE(class In)
(requires submit_detail::AutoSenderTo<In, AN...>)
In operator()(In in) {
auto out{::pushmi::detail::out_from_fn<In>()(std::move(args_))};
::pushmi::submit(in, std::move(out));
return in;
}
PUSHMI_TEMPLATE(class In)
(requires submit_detail::AutoTimeSenderTo<In, AN...>)
In operator()(In in) {
auto out{::pushmi::detail::out_from_fn<In>()(std::move(args_))};
::pushmi::submit(in, ::pushmi::now(in), std::move(out));
return in;
}
};
public:
template <class... AN>
auto operator()(AN&&... an) const {
return submit_fn::fn<AN...>{{(AN&&) an...}};
}
};
struct submit_at_fn {
private:
template <class TP, class...AN>
struct fn {
TP at_;
std::tuple<AN...> args_;
PUSHMI_TEMPLATE(class In)
(requires submit_detail::AutoTimeSenderTo<In, AN...>)
In operator()(In in) {
auto out{::pushmi::detail::out_from_fn<In>()(std::move(args_))};
::pushmi::submit(in, std::move(at_), std::move(out));
return in;
}
};
public:
PUSHMI_TEMPLATE(class TP, class...AN)
(requires Regular<TP>)
auto operator()(TP at, AN... an) const {
return submit_at_fn::fn<TP, AN...>{std::move(at), {(AN&&) an...}};
}
};
struct submit_after_fn { template <class T>
private: void value(T t) {
template <class D, class... AN> if (done_) {
struct fn { return;
D after_; }
std::tuple<AN...> args_; done_ = true;
PUSHMI_TEMPLATE(class In) out_.value(std::move(t));
(requires submit_detail::AutoTimeSenderTo<In, AN...>) }
In operator()(In in) {
// TODO - only move, move-only types..
// if out can be copied, then submit can be called multiple
// times..
auto out{::pushmi::detail::out_from_fn<In>()(std::move(args_))};
auto at = ::pushmi::now(in) + std::move(after_);
::pushmi::submit(in, std::move(at), std::move(out));
return in;
}
};
public:
PUSHMI_TEMPLATE(class D, class...AN)
(requires Regular<D>)
auto operator()(D after, AN... an) const {
return submit_after_fn::fn<D, AN...>{std::move(after), {(AN&&) an...}};
}
};
struct blocking_submit_fn { template <class E>
private: void error(E e) {
// TODO - only move, move-only types.. if (done_) {
// if out can be copied, then submit can be called multiple return;
// times.. }
template <class... AN> done_ = true;
struct fn { out_.error(std::move(e));
std::tuple<AN...> args_; }
template <bool IsTimeSender, class In> void stopping() {
In impl_(In in) { if (done_) {
bool done = false; return;
std::condition_variable signaled; }
auto out{::pushmi::detail::out_from_fn<In>()( done_ = true;
std::move(args_), *stopped_ = true;
on_value(constrain(pushmi::lazy::Receiver<_1, is_single<>>, out_.stopping();
[&](auto out, auto&& v) { }
using V = remove_cvref_t<decltype(v)>;
PUSHMI_IF_CONSTEXPR( ((bool)Time<V>) (
// to keep the blocking semantics, make sure that the
// nested submits block here to prevent a spurious
// completion signal
auto nest = ::pushmi::nested_trampoline();
::pushmi::submit(nest, ::pushmi::now(nest), std::move(out));
) else (
::pushmi::set_value(out, id((V&&) v));
))
done = true;
signaled.notify_all();
}
)),
on_error(constrain(pushmi::lazy::NoneReceiver<_1, _2>,
[&](auto out, auto e) noexcept {
::pushmi::set_error(out, std::move(e));
done = true;
signaled.notify_all();
}
)),
on_done(constrain(pushmi::lazy::Receiver<_1>,
[&](auto out){
::pushmi::set_done(out);
done = true;
signaled.notify_all();
}
))
)};
PUSHMI_IF_CONSTEXPR( (IsTimeSender) (
id(::pushmi::submit)(in, id(::pushmi::now)(in), std::move(out));
) else (
id(::pushmi::submit)(in, std::move(out));
))
std::mutex lock;
std::unique_lock<std::mutex> guard{lock};
signaled.wait(guard, [&]{
return done;
});
return in;
}
PUSHMI_TEMPLATE(class In) template <class Producer>
(requires submit_detail::AutoSenderTo<In, AN...>) void starting(RefWrapper<Producer> up) {
In operator()(In in) { upProxy_ =
return this->impl_<false>(std::move(in)); producer_proxy<Producer>{std::move(up), stopped_, std::move(exec_)};
} out_.starting(wrap_ref(upProxy_));
PUSHMI_TEMPLATE(class In) }
(requires submit_detail::AutoTimeSenderTo<In, AN...>) };
In operator()(In in) {
return this->impl_<true>(std::move(in)); public:
start_on(executor_factory_type&& ef, in_type&& in)
: factory_(std::move(ef)), in_(std::move(in)) {}
template <class Out>
auto then(Out out) {
auto exec = factory_();
auto myout = out_on<Out, decltype(exec)>{std::move(out), exec};
exec | execute([in = in_, myout = std::move(myout)](auto) mutable {
in.then(std::move(myout));
});
} }
}; };
public:
template <class... AN>
auto operator()(AN... an) const {
return blocking_submit_fn::fn<AN...>{{(AN&&) an...}};
}
};
template <class T> public:
struct get_fn { explicit fsdon(executor_factory_type&& ef) : factory_(std::move(ef)) {}
// TODO constrain this better
PUSHMI_TEMPLATE (class In) template <class In>
(requires Sender<In>) auto operator()(In in) {
T operator()(In in) const { return start_on<In>{std::move(factory_), std::move(in)};
pushmi::detail::opt<T> result_;
std::exception_ptr ep_;
auto out = make_single(
on_value([&](T t){ result_ = std::move(t); }),
on_error(
[&](auto e) noexcept { ep_ = std::make_exception_ptr(e); },
[&](std::exception_ptr ep) noexcept { ep_ = ep; })
);
using Out = decltype(out);
static_assert(SenderTo<In, Out, is_single<>> ||
TimeSenderTo<In, Out, is_single<>>,
"'In' does not deliver value compatible with 'T' to 'Out'");
blocking_submit_fn{}(std::move(out))(in);
if (!!ep_) { std::rethrow_exception(ep_); }
return std::move(*result_);
} }
}; };
} // namespace detail } // namespace detail
namespace operators { namespace fsd {
PUSHMI_INLINE_VAR constexpr detail::submit_fn submit{}; template <class ExecutorFactory>
PUSHMI_INLINE_VAR constexpr detail::submit_at_fn submit_at{}; auto on(ExecutorFactory factory) {
PUSHMI_INLINE_VAR constexpr detail::submit_after_fn submit_after{}; return detail::fsdon<ExecutorFactory>{std::move(factory)};
PUSHMI_INLINE_VAR constexpr detail::blocking_submit_fn blocking_submit{}; }
template <class T> } // namespace fsd
PUSHMI_INLINE_VAR constexpr detail::get_fn<T> get{}; #endif
} // namespace operators
} // namespace pushmi } // namespace pushmi
// clang-format off // clang-format off
...@@ -9507,6 +9647,112 @@ auto via(ExecutorFactory factory) { ...@@ -9507,6 +9647,112 @@ auto via(ExecutorFactory factory) {
} // namespace fsd } // namespace fsd
#endif #endif
} // namespace pushmi
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
//#pragma once
// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//#include "../single.h"
//#include "submit.h"
//#include "extension_operators.h"
//#include "via.h"
namespace pushmi {
namespace detail {
struct request_via_fn {
template<typename In>
struct semisender {
In in;
template<class... AN>
auto via(AN&&... an) {
return in | ::pushmi::operators::via((AN&&) an...);
}
};
auto operator()() const;
};
auto request_via_fn::operator()() const {
return constrain(lazy::Sender<_1>, [](auto in) {
using In = decltype(in);
return semisender<In>{in};
});
}
} // namespace detail
namespace operators {
PUSHMI_INLINE_VAR constexpr detail::request_via_fn request_via{};
} // namespace operators
PUSHMI_TEMPLATE(class To, class In)
(requires Same<To, is_sender<>> && Sender<_1>)
auto via_cast(In in) {
return in;
}
PUSHMI_TEMPLATE(class To, class In)
(requires Same<To, is_sender<>>)
auto via_cast(detail::request_via_fn::semisender<In> ss) {
return ss.in;
}
} // namespace pushmi
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
//#pragma once
// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//#include "../single.h"
//#include "submit.h"
//#include "extension_operators.h"
//#include "../subject.h"
namespace pushmi {
namespace detail {
template<class T>
struct share_fn {
auto operator()() const;
};
template<class T>
auto share_fn<T>::operator()() const {
return constrain(lazy::Sender<_1>, [](auto in) {
using In = decltype(in);
subject<T, properties_t<In>> sub;
PUSHMI_IF_CONSTEXPR( ((bool)TimeSender<In>) (
::pushmi::submit(in, ::pushmi::now(id(in)), sub.receiver());
) else (
::pushmi::submit(id(in), sub.receiver());
));
return sub;
});
}
} // namespace detail
namespace operators {
template<class T>
PUSHMI_INLINE_VAR constexpr detail::share_fn<T> share{};
} // namespace operators
} // namespace pushmi } // namespace pushmi
#endif // PUSHMI_SINGLE_HEADER #endif // PUSHMI_SINGLE_HEADER
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
// This source code is licensed under the MIT license found in the // This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree. // LICENSE file in the root directory of this source tree.
#include <vector>
#include <pushmi/time_single_deferred.h> #include <pushmi/time_single_deferred.h>
namespace pushmi { namespace pushmi {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment