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

change copyright headers and apply some clang format

Summary:
changed the copyright headers to match folly
ran clang format in places that it did not mess up too badly

almost entirely whitespace changes

Reviewed By: Orvid

Differential Revision: D10450516

fbshipit-source-id: dc00a3952ee63d9ceb218aacb8f5f55a7c171170
parent a25bbf7c
#define NONIUS_RUNNER
#define concept Concept
#include <nonius/nonius.h++>
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <chrono> #include <chrono>
#include <cstdint> #include <cstdint>
......
This diff is collapsed.
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/receiver.h> #include <folly/experimental/pushmi/receiver.h>
#include <folly/experimental/pushmi/executor.h> #include <folly/experimental/pushmi/executor.h>
......
// clang-format off
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <type_traits> #include <type_traits>
...@@ -401,7 +411,8 @@ PUSHMI_PP_IGNORE_CXX2A_COMPAT_BEGIN ...@@ -401,7 +411,8 @@ PUSHMI_PP_IGNORE_CXX2A_COMPAT_BEGIN
#else #else
#define PUSHMI_BROKEN_SUBSUMPTION(...) __VA_ARGS__ #define PUSHMI_BROKEN_SUBSUMPTION(...) __VA_ARGS__
#define PUSHMI_TYPE_CONSTRAINT(...) class #define PUSHMI_TYPE_CONSTRAINT(...) class
// bool() is used to prevent 'error: pasting "PUSHMI_PP_REQUIRES_PROBE_" and "::" does not give a valid preprocessing token' // bool() is used to prevent 'error: pasting "PUSHMI_PP_REQUIRES_PROBE_" and
// "::" does not give a valid preprocessing token'
#define PUSHMI_EXP(...) bool(::pushmi::expAnd(__VA_ARGS__)) #define PUSHMI_EXP(...) bool(::pushmi::expAnd(__VA_ARGS__))
#define PUSHMI_AND , #define PUSHMI_AND ,
#endif #endif
...@@ -439,91 +450,91 @@ struct Or; ...@@ -439,91 +450,91 @@ struct Or;
template <class T> template <class T>
struct Not { struct Not {
explicit constexpr operator bool() const noexcept { explicit constexpr operator bool() const noexcept {
return !(bool) T{}; return !(bool)T{};
} }
PUSHMI_TEMPLATE (class This = Not, bool B) PUSHMI_TEMPLATE(class This = Not, bool B)
(requires B == (bool) This{}) (requires B == (bool)This{}) constexpr
constexpr operator std::integral_constant<bool, B>() const noexcept { operator std::integral_constant<bool, B>() const noexcept {
return {}; return {};
} }
constexpr auto operator!() const noexcept { constexpr auto operator!() const noexcept {
return T{}; return T{};
} }
template <class That> template <class That>
constexpr auto operator&&(That) const noexcept { constexpr auto operator&&(That) const noexcept {
return And<Not, That>{}; return And<Not, That>{};
} }
template <class That> template <class That>
constexpr auto operator||(That) const noexcept { constexpr auto operator||(That) const noexcept {
return Or<Not, That>{}; return Or<Not, That>{};
} }
}; };
template <class T, class U> template <class T, class U>
struct And { struct And {
explicit constexpr operator bool() const noexcept { explicit constexpr operator bool() const noexcept {
return (bool) std::conditional_t<(bool) T{}, U, std::false_type>{}; return (bool)std::conditional_t<(bool)T{}, U, std::false_type>{};
} }
PUSHMI_TEMPLATE (class This = And, bool B) PUSHMI_TEMPLATE(class This = And, bool B)
(requires B == (bool) This{}) (requires B == (bool)This{}) constexpr
constexpr operator std::integral_constant<bool, B>() const noexcept { operator std::integral_constant<bool, B>() const noexcept {
return {}; return {};
} }
constexpr auto operator!() const noexcept { constexpr auto operator!() const noexcept {
return Not<And>{}; return Not<And>{};
} }
template <class That> template <class That>
constexpr auto operator&&(That) const noexcept { constexpr auto operator&&(That) const noexcept {
return And<And, That>{}; return And<And, That>{};
} }
template <class That> template <class That>
constexpr auto operator||(That) const noexcept { constexpr auto operator||(That) const noexcept {
return Or<And, That>{}; return Or<And, That>{};
} }
}; };
template <class T, class U> template <class T, class U>
struct Or { struct Or {
explicit constexpr operator bool() const noexcept { explicit constexpr operator bool() const noexcept {
return (bool) std::conditional_t<(bool) T{}, std::true_type, U>{}; return (bool)std::conditional_t<(bool)T{}, std::true_type, U>{};
} }
PUSHMI_TEMPLATE (class This = Or, bool B) PUSHMI_TEMPLATE(class This = Or, bool B)
(requires B == (bool) This{}) (requires B == (bool)This{}) constexpr
constexpr operator std::integral_constant<bool, B>() const noexcept { operator std::integral_constant<bool, B>() const noexcept {
return {}; return {};
} }
constexpr auto operator!() const noexcept { constexpr auto operator!() const noexcept {
return Not<Or>{}; return Not<Or>{};
} }
template <class That> template <class That>
constexpr auto operator&&(That) const noexcept { constexpr auto operator&&(That) const noexcept {
return And<Or, That>{}; return And<Or, That>{};
} }
template <class That> template <class That>
constexpr auto operator||(That) const noexcept { constexpr auto operator||(That) const noexcept {
return Or<Or, That>{}; return Or<Or, That>{};
} }
}; };
} // namespace detail } // namespace detail
} // namespace concepts } // namespace concepts
namespace isolated { namespace isolated {
template<class T0> template <class T0>
constexpr auto expAnd(T0&& t0) { constexpr auto expAnd(T0&& t0) {
return (T0&&)t0; return (T0 &&) t0;
} }
template<class T0, class... TN> template <class T0, class... TN>
constexpr auto expAnd(T0&&, TN&&... tn) { constexpr auto expAnd(T0&&, TN&&... tn) {
return concepts::detail::And<T0, decltype(isolated::expAnd((TN&&)tn...))>{}; return concepts::detail::And<T0, decltype(isolated::expAnd((TN &&) tn...))>{};
} }
} } // namespace isolated
template<class... TN> template <class... TN>
constexpr auto expAnd(TN&&... tn) { constexpr auto expAnd(TN&&... tn) {
return isolated::expAnd((TN&&)tn...); return isolated::expAnd((TN &&) tn...);
} }
template <class T> template <class T>
...@@ -532,8 +543,7 @@ constexpr bool implicitly_convertible_to(T) { ...@@ -532,8 +543,7 @@ constexpr bool implicitly_convertible_to(T) {
} }
#ifdef __clang__ #ifdef __clang__
template <bool B> template <bool B>
std::enable_if_t<B> requires_() std::enable_if_t<B> requires_() {}
{}
#else #else
template <bool B> template <bool B>
PUSHMI_INLINE_VAR constexpr std::enable_if_t<B, int> requires_ = 0; PUSHMI_INLINE_VAR constexpr std::enable_if_t<B, int> requires_ = 0;
......
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <functional> #include <functional>
...@@ -13,27 +22,28 @@ ...@@ -13,27 +22,28 @@
namespace pushmi { namespace pushmi {
PUSHMI_INLINE_VAR constexpr struct invoke_fn { PUSHMI_INLINE_VAR constexpr struct invoke_fn {
private: private:
template <class F> template <class F>
using mem_fn_t = decltype(std::mem_fn(std::declval<F>())); using mem_fn_t = decltype(std::mem_fn(std::declval<F>()));
public:
public:
template <class F, class... As> template <class F, class... As>
auto operator()(F&& f, As&&...as) const auto operator()(F&& f, As&&... as) const
noexcept(noexcept(((F&&) f)((As&&) as...))) -> noexcept(noexcept(((F &&) f)((As &&) as...)))
decltype(((F&&) f)((As&&) as...)) { -> decltype(((F &&) f)((As &&) as...)) {
return ((F&&) f)((As&&) as...); return ((F &&) f)((As &&) as...);
} }
template <class F, class... As> template <class F, class... As>
auto operator()(F&& f, As&&...as) const auto operator()(F&& f, As&&... as) const
noexcept(noexcept(std::declval<mem_fn_t<F>>()((As&&) as...))) -> noexcept(noexcept(std::declval<mem_fn_t<F>>()((As &&) as...)))
decltype(std::mem_fn(f)((As&&) as...)) { -> decltype(std::mem_fn(f)((As &&) as...)) {
return std::mem_fn(f)((As&&) as...); return std::mem_fn(f)((As &&) as...);
} }
} invoke {}; } invoke{};
template <class F, class...As> template <class F, class... As>
using invoke_result_t = using invoke_result_t =
decltype(pushmi::invoke(std::declval<F>(), std::declval<As>()...)); decltype(pushmi::invoke(std::declval<F>(), std::declval<As>()...));
PUSHMI_CONCEPT_DEF( PUSHMI_CONCEPT_DEF(
template (class F, class... Args) template (class F, class... Args)
......
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Usage: // Usage:
...@@ -145,41 +154,42 @@ namespace detail { ...@@ -145,41 +154,42 @@ namespace detail {
template <bool> template <bool>
struct select { struct select {
template <class R, class = std::enable_if_t<!std::is_void<R>::value>> template <class R, class = std::enable_if_t<!std::is_void<R>::value>>
struct eat_return { struct eat_return {
R value_; R value_;
template <class T>
constexpr R operator->*(T&&) {
return static_cast<R&&>(value_);
}
};
struct eat {
template <class T>
constexpr void operator->*(T&&) {}
};
template <class T> template <class T>
constexpr auto operator->*(T&& t) -> eat_return<decltype(t(::pushmi::detail::id_fn{}))> { constexpr R operator->*(T&&) {
return {t(::pushmi::detail::id_fn{})}; return static_cast<R&&>(value_);
} }
};
struct eat {
template <class T> template <class T>
constexpr auto operator->*(T&& t) const -> eat { constexpr void operator->*(T&&) {}
return t(::pushmi::detail::id_fn{}), void(), eat{}; };
} template <class T>
constexpr auto operator->*(T&& t)
-> eat_return<decltype(t(::pushmi::detail::id_fn{}))> {
return {t(::pushmi::detail::id_fn{})};
}
template <class T>
constexpr auto operator->*(T&& t) const -> eat {
return t(::pushmi::detail::id_fn{}), void(), eat{};
}
}; };
template <> template <>
struct select<false> { struct select<false> {
struct eat { struct eat {
template <class T>
constexpr auto operator->*(T&& t) -> decltype(auto) {
return t(::pushmi::detail::id_fn{});
}
};
template <class T> template <class T>
constexpr eat operator->*(T&&) { constexpr auto operator->*(T&& t) -> decltype(auto) {
return {}; return t(::pushmi::detail::id_fn{});
} }
};
template <class T>
constexpr eat operator->*(T&&) {
return {};
}
}; };
} } // namespace detail
} } // namespace pushmi
#endif #endif
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if __cpp_lib_optional >= 201606 #if __cpp_lib_optional >= 201606
#include <optional> // @manual #include <optional> // @manual
...@@ -16,18 +25,18 @@ namespace detail { ...@@ -16,18 +25,18 @@ namespace detail {
#if __cpp_lib_optional >= 201606 #if __cpp_lib_optional >= 201606
template <class T> template <class T>
struct opt : private std::optional<T> { struct opt : private std::optional<T> {
opt() = default; opt() = default;
opt& operator=(T&& t) { opt& operator=(T&& t) {
this->std::optional<T>::operator=(std::move(t)); this->std::optional<T>::operator=(std::move(t));
return *this; return *this;
} }
using std::optional<T>::operator*; using std::optional<T>::operator*;
using std::optional<T>::operator bool; using std::optional<T>::operator bool;
}; };
#else #else
template <class T> template <class T>
struct opt { struct opt {
private: private:
bool empty_ = true; bool empty_ = true;
std::aligned_union_t<0, T> data_; std::aligned_union_t<0, T> data_;
T* ptr() { T* ptr() {
...@@ -42,40 +51,43 @@ private: ...@@ -42,40 +51,43 @@ private:
empty_ = true; empty_ = true;
} }
} }
public:
public:
opt() = default; opt() = default;
opt(T&& t) noexcept(std::is_nothrow_move_constructible<T>::value) { opt(T&& t) noexcept(std::is_nothrow_move_constructible<T>::value) {
::new(ptr()) T(std::move(t)); ::new (ptr()) T(std::move(t));
empty_ = false; empty_ = false;
} }
opt(const T& t) { opt(const T& t) {
::new(ptr()) T(t); ::new (ptr()) T(t);
empty_ = false; empty_ = false;
} }
opt(opt&& that) noexcept(std::is_nothrow_move_constructible<T>::value) { opt(opt&& that) noexcept(std::is_nothrow_move_constructible<T>::value) {
if (that) { if (that) {
::new(ptr()) T(std::move(*that)); ::new (ptr()) T(std::move(*that));
empty_ = false; empty_ = false;
that.reset(); that.reset();
} }
} }
opt(const opt& that) { opt(const opt& that) {
if (that) { if (that) {
::new(ptr()) T(*that); ::new (ptr()) T(*that);
empty_ = false; empty_ = false;
} }
} }
~opt() { reset(); } ~opt() {
opt& operator=(opt&& that) reset();
noexcept(std::is_nothrow_move_constructible<T>::value && }
std::is_nothrow_move_assignable<T>::value) { opt& operator=(opt&& that) noexcept(
std::is_nothrow_move_constructible<T>::value&&
std::is_nothrow_move_assignable<T>::value) {
if (*this && that) { if (*this && that) {
**this = std::move(*that); **this = std::move(*that);
that.reset(); that.reset();
} else if (*this) { } else if (*this) {
reset(); reset();
} else if (that) { } else if (that) {
::new(ptr()) T(std::move(*that)); ::new (ptr()) T(std::move(*that));
empty_ = false; empty_ = false;
} }
return *this; return *this;
...@@ -86,17 +98,18 @@ public: ...@@ -86,17 +98,18 @@ public:
} else if (*this) { } else if (*this) {
reset(); reset();
} else if (that) { } else if (that) {
::new(ptr()) T(*that); ::new (ptr()) T(*that);
empty_ = false; empty_ = false;
} }
return *this; return *this;
} }
opt& operator=(T&& t) noexcept(std::is_nothrow_move_constructible<T>::value && opt& operator=(T&& t) noexcept(
std::is_nothrow_move_assignable<T>::value) { std::is_nothrow_move_constructible<T>::value&&
std::is_nothrow_move_assignable<T>::value) {
if (*this) if (*this)
**this = std::move(t); **this = std::move(t);
else { else {
::new(ptr()) T(std::move(t)); ::new (ptr()) T(std::move(t));
empty_ = false; empty_ = false;
} }
return *this; return *this;
...@@ -105,7 +118,7 @@ public: ...@@ -105,7 +118,7 @@ public:
if (*this) if (*this)
**this = t; **this = t;
else { else {
::new(ptr()) T(t); ::new (ptr()) T(t);
empty_ = false; empty_ = false;
} }
return *this; return *this;
......
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/forwards.h> #include <folly/experimental/pushmi/forwards.h>
namespace pushmi { namespace pushmi {
// template <class T, class Dual> // template <class T, class Dual>
// struct entangled { // struct entangled {
// T t; // T t;
...@@ -84,7 +94,11 @@ struct entangled { ...@@ -84,7 +94,11 @@ struct entangled {
// have to hold *both* locks to write any of either entangled object's // have to hold *both* locks to write any of either entangled object's
// metadata, but need only one to read it. // metadata, but need only one to read it.
int expected = kUnlocked; int expected = kUnlocked;
if (!stateMachine.compare_exchange_weak(expected, kLocked, std::memory_order_seq_cst, std::memory_order_relaxed)) { if (!stateMachine.compare_exchange_weak(
expected,
kLocked,
std::memory_order_seq_cst,
std::memory_order_relaxed)) {
return false; return false;
} }
// Having *either* object local-locked protects the data in both objects. // Having *either* object local-locked protects the data in both objects.
...@@ -93,7 +107,8 @@ struct entangled { ...@@ -93,7 +107,8 @@ struct entangled {
return true; return true;
} }
expected = kUnlocked; expected = kUnlocked;
if (dual->stateMachine.compare_exchange_strong(expected, kLocked, std::memory_order_seq_cst)) { if (dual->stateMachine.compare_exchange_strong(
expected, kLocked, std::memory_order_seq_cst)) {
return true; return true;
} }
// We got here, and so hit the race; we're deadlocked if we stick to // We got here, and so hit the race; we're deadlocked if we stick to
...@@ -105,7 +120,8 @@ struct entangled { ...@@ -105,7 +120,8 @@ struct entangled {
if ((uintptr_t)this < (uintptr_t)dual) { if ((uintptr_t)this < (uintptr_t)dual) {
// I get to win the race. I'll acquire the locks, but have to make sure // I get to win the race. I'll acquire the locks, but have to make sure
// my memory stays valid until the other thread acknowledges its loss. // my memory stays valid until the other thread acknowledges its loss.
while (stateMachine.load(std::memory_order_relaxed) != kLockedAndLossAcknowledged) { while (stateMachine.load(std::memory_order_relaxed) !=
kLockedAndLossAcknowledged) {
// Spin. // Spin.
} }
stateMachine.store(kLocked, std::memory_order_relaxed); stateMachine.store(kLocked, std::memory_order_relaxed);
...@@ -113,7 +129,8 @@ struct entangled { ...@@ -113,7 +129,8 @@ struct entangled {
} else { } else {
// I lose the race, but have to coordinate with the winning thread, so // I lose the race, but have to coordinate with the winning thread, so
// that it knows that I'm not about to try to touch it's data // that it knows that I'm not about to try to touch it's data
dual->stateMachine.store(kLockedAndLossAcknowledged, std::memory_order_relaxed); dual->stateMachine.store(
kLockedAndLossAcknowledged, std::memory_order_relaxed);
return false; return false;
} }
} }
...@@ -194,11 +211,11 @@ struct entangled { ...@@ -194,11 +211,11 @@ struct entangled {
}; };
template <class First, class Second> template <class First, class Second>
using entangled_pair = std::pair<entangled<First, Second>, entangled<Second, First>>; using entangled_pair =
std::pair<entangled<First, Second>, entangled<Second, First>>;
template <class First, class Second> template <class First, class Second>
auto entangle(First f, Second s) auto entangle(First f, Second s) -> entangled_pair<First, Second> {
-> entangled_pair<First, Second> {
entangled<First, Second> ef(std::move(f)); entangled<First, Second> ef(std::move(f));
entangled<Second, First> es(std::move(s)); entangled<Second, First> es(std::move(s));
ef.dual = std::addressof(es); ef.dual = std::addressof(es);
...@@ -209,8 +226,12 @@ auto entangle(First f, Second s) ...@@ -209,8 +226,12 @@ auto entangle(First f, Second s)
template <class T, class Dual> template <class T, class Dual>
struct locked_entangled_pair : std::pair<T*, Dual*> { struct locked_entangled_pair : std::pair<T*, Dual*> {
entangled<T, Dual>* e; entangled<T, Dual>* e;
~locked_entangled_pair(){if (!!e) {e->unlockBoth();}} ~locked_entangled_pair() {
explicit locked_entangled_pair(entangled<T, Dual>& e) : e(std::addressof(e)){ if (!!e) {
e->unlockBoth();
}
}
explicit locked_entangled_pair(entangled<T, Dual>& e) : e(std::addressof(e)) {
this->e->lockBoth(); this->e->lockBoth();
this->first = std::addressof(this->e->t); this->first = std::addressof(this->e->t);
this->second = !!this->e->dual ? std::addressof(this->e->dual->t) : nullptr; this->second = !!this->e->dual ? std::addressof(this->e->dual->t) : nullptr;
...@@ -218,9 +239,13 @@ struct locked_entangled_pair : std::pair<T*, Dual*> { ...@@ -218,9 +239,13 @@ struct locked_entangled_pair : std::pair<T*, Dual*> {
locked_entangled_pair() = delete; locked_entangled_pair() = delete;
locked_entangled_pair(const locked_entangled_pair&) = delete; locked_entangled_pair(const locked_entangled_pair&) = delete;
locked_entangled_pair& operator=(const locked_entangled_pair&) = delete; locked_entangled_pair& operator=(const locked_entangled_pair&) = delete;
locked_entangled_pair(locked_entangled_pair&& o) : std::pair<T*, Dual*>(o), e(o.e) {o.e = nullptr;} locked_entangled_pair(locked_entangled_pair&& o)
locked_entangled_pair& operator=(locked_entangled_pair&& o){ : std::pair<T*, Dual*>(o), e(o.e) {
static_cast<std::pair<T*, Dual*>&>(*this) = static_cast<std::pair<T*, Dual*>&&>(o); o.e = nullptr;
}
locked_entangled_pair& operator=(locked_entangled_pair&& o) {
static_cast<std::pair<T*, Dual*>&>(*this) =
static_cast<std::pair<T*, Dual*>&&>(o);
e = o.e; e = o.e;
o.e = nullptr; o.e = nullptr;
return *this; return *this;
...@@ -228,7 +253,7 @@ struct locked_entangled_pair : std::pair<T*, Dual*> { ...@@ -228,7 +253,7 @@ struct locked_entangled_pair : std::pair<T*, Dual*> {
}; };
template <class T, class Dual> template <class T, class Dual>
locked_entangled_pair<T, Dual> lock_both(entangled<T, Dual>& e){ locked_entangled_pair<T, Dual> lock_both(entangled<T, Dual>& e) {
return locked_entangled_pair<T, Dual>{e}; return locked_entangled_pair<T, Dual>{e};
} }
...@@ -237,27 +262,31 @@ struct shared_entangled : std::shared_ptr<T> { ...@@ -237,27 +262,31 @@ struct shared_entangled : std::shared_ptr<T> {
Dual* dual; Dual* dual;
std::mutex* lock; std::mutex* lock;
template<class P> template <class P>
explicit shared_entangled(std::shared_ptr<P>& p, T& t, Dual& d, std::mutex& l) : explicit shared_entangled(std::shared_ptr<P>& p, T& t, Dual& d, std::mutex& l)
std::shared_ptr<T>(p, std::addressof(t)), dual(std::addressof(d)), lock(std::addressof(l)){ : std::shared_ptr<T>(p, std::addressof(t)),
} dual(std::addressof(d)),
lock(std::addressof(l)) {}
shared_entangled() = delete; shared_entangled() = delete;
}; };
template <class First, class Second> template <class First, class Second>
using shared_entangled_pair = std::pair<shared_entangled<First, Second>, shared_entangled<Second, First>>; using shared_entangled_pair =
std::pair<shared_entangled<First, Second>, shared_entangled<Second, First>>;
template <class First, class Second> template <class First, class Second>
auto shared_entangle(First f, Second s) auto shared_entangle(First f, Second s)
-> shared_entangled_pair<First, Second> { -> shared_entangled_pair<First, Second> {
struct storage { struct storage {
storage(First&& f, Second&& s) : p((First&&) f, (Second&&) s) {} storage(First&& f, Second&& s) : p((First &&) f, (Second &&) s) {}
std::tuple<First, Second> p; std::tuple<First, Second> p;
std::mutex lock; std::mutex lock;
}; };
auto p = std::make_shared<storage>(std::move(f), std::move(s)); auto p = std::make_shared<storage>(std::move(f), std::move(s));
shared_entangled<First, Second> ef(p, std::get<0>(p->p), std::get<1>(p->p), p->lock); shared_entangled<First, Second> ef(
shared_entangled<Second, First> es(p, std::get<1>(p->p), std::get<0>(p->p), p->lock); p, std::get<0>(p->p), std::get<1>(p->p), p->lock);
shared_entangled<Second, First> es(
p, std::get<1>(p->p), std::get<0>(p->p), p->lock);
return {std::move(ef), std::move(es)}; return {std::move(ef), std::move(es)};
} }
...@@ -269,7 +298,8 @@ struct locked_shared_entangled_pair : std::pair<T*, Dual*> { ...@@ -269,7 +298,8 @@ struct locked_shared_entangled_pair : std::pair<T*, Dual*> {
e.lock->unlock(); e.lock->unlock();
} }
} }
explicit locked_shared_entangled_pair(shared_entangled<T, Dual>& e) : e(std::move(e)){ explicit locked_shared_entangled_pair(shared_entangled<T, Dual>& e)
: e(std::move(e)) {
this->e.lock->lock(); this->e.lock->lock();
this->first = this->e.get(); this->first = this->e.get();
this->second = this->e.dual; this->second = this->e.dual;
...@@ -277,9 +307,8 @@ struct locked_shared_entangled_pair : std::pair<T*, Dual*> { ...@@ -277,9 +307,8 @@ struct locked_shared_entangled_pair : std::pair<T*, Dual*> {
locked_shared_entangled_pair() = delete; locked_shared_entangled_pair() = delete;
}; };
template <class T, class Dual> template <class T, class Dual>
locked_shared_entangled_pair<T, Dual> lock_both(shared_entangled<T, Dual>& e){ locked_shared_entangled_pair<T, Dual> lock_both(shared_entangled<T, Dual>& e) {
return locked_shared_entangled_pair<T, Dual>{e}; return locked_shared_entangled_pair<T, Dual>{e};
} }
......
#pragma once #pragma once
/*
// Copyright (c) 2018-present, Facebook, Inc. * Copyright 2018-present Facebook, Inc.
// *
// This source code is licensed under the MIT license found in the * Licensed under the Apache License, Version 2.0 (the "License");
// LICENSE file in the root directory of this source tree. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/single_sender.h> #include <folly/experimental/pushmi/single_sender.h>
...@@ -12,7 +22,13 @@ namespace pushmi { ...@@ -12,7 +22,13 @@ namespace pushmi {
namespace operators { namespace operators {
PUSHMI_INLINE_VAR constexpr struct bulk_fn { PUSHMI_INLINE_VAR constexpr struct bulk_fn {
template<class F, class ShapeBegin, class ShapeEnd, class Target, class IF, class RS> template <
class F,
class ShapeBegin,
class ShapeEnd,
class Target,
class IF,
class RS>
auto operator()( auto operator()(
F&& func, F&& func,
ShapeBegin sb, ShapeBegin sb,
...@@ -20,18 +36,28 @@ PUSHMI_INLINE_VAR constexpr struct bulk_fn { ...@@ -20,18 +36,28 @@ PUSHMI_INLINE_VAR constexpr struct bulk_fn {
Target&& driver, Target&& driver,
IF&& initFunc, IF&& initFunc,
RS&& selector) const { RS&& selector) const {
return [func, sb, se, driver, initFunc, selector](auto in){ return [func, sb, se, driver, initFunc, selector](auto in) {
return make_single_sender( return make_single_sender(
[in, func, sb, se, driver, initFunc, selector](auto out) mutable { [in, func, sb, se, driver, initFunc, selector](auto out) mutable {
submit(in, make_receiver(std::move(out), submit(
[func, sb, se, driver, initFunc, selector](auto& out, auto input) { in,
driver(initFunc, selector, std::move(input), func, sb, se, std::move(out)); make_receiver(
} std::move(out),
)); [func, sb, se, driver, initFunc, selector](
}); auto& out, auto input) {
driver(
initFunc,
selector,
std::move(input),
func,
sb,
se,
std::move(out));
}));
});
}; };
} }
} bulk {}; } bulk{};
} // namespace operators } // namespace operators
......
#include <vector> /*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <vector>
#include <folly/experimental/pushmi/examples/pool.h> #include <folly/experimental/pushmi/examples/pool.h>
...@@ -12,91 +27,80 @@ ...@@ -12,91 +27,80 @@
using namespace pushmi::aliases; using namespace pushmi::aliases;
struct f_t {}; struct f_t {};
f_t f(){ f_t f() {
return {}; return {};
} }
struct g_t {}; struct g_t {};
g_t g(f_t){ g_t g(f_t) {
return {}; return {};
} }
// these expressions are read backward, bottom-right to top-left // these expressions are read backward, bottom-right to top-left
template<class CPUExecutor, class IOExecutor> template <class CPUExecutor, class IOExecutor>
void lisp(CPUExecutor cpu, IOExecutor io) { void lisp(CPUExecutor cpu, IOExecutor io) {
// f on cpu - g on cpu (implicit: a single task on the cpu executor runs all the functions) // f on cpu - g on cpu (implicit: a single task on the cpu executor runs all
op::submit([](g_t){})( // the functions)
op::transform([](f_t ft) {return g(ft);})( op::submit([](g_t) {})(op::transform([](f_t ft) { return g(ft); })(
op::transform([](auto){ return f(); })( op::transform([](auto) { return f(); })(cpu)));
cpu)));
// f on cpu - g on cpu (explicit: the first cpu task runs f and a second cpu
// f on cpu - g on cpu (explicit: the first cpu task runs f and a second cpu task runs g) // task runs g)
op::submit([](g_t){})( op::submit([](g_t) {})(op::transform([](f_t ft) { return g(ft); })(
op::transform([](f_t ft) {return g(ft);})( op::via(mi::strands(cpu))(op::transform([](auto) { return f(); })(cpu))));
op::via(mi::strands(cpu))(
op::transform([](auto){ return f(); })(
cpu))));
// f on io - g on cpu // f on io - g on cpu
op::submit([](g_t){})( op::submit([](g_t) {})(op::transform([](f_t ft) { return g(ft); })(
op::transform([](f_t ft) {return g(ft);})( op::via(mi::strands(cpu))(op::transform([](auto) { return f(); })(io))));
op::via(mi::strands(cpu))(
op::transform([](auto){ return f(); })(
io))));
} }
template<class CPUExecutor, class IOExecutor> template <class CPUExecutor, class IOExecutor>
void sugar(CPUExecutor cpu, IOExecutor io) { void sugar(CPUExecutor cpu, IOExecutor io) {
// f on cpu - g on cpu (implicit: a single task on the cpu executor runs all the functions) // f on cpu - g on cpu (implicit: a single task on the cpu executor runs all
cpu | // the functions)
op::transform([](auto){ return f(); }) | cpu | op::transform([](auto) { return f(); }) |
op::transform([](f_t ft) {return g(ft);}) | op::transform([](f_t ft) { return g(ft); }) | op::submit([](g_t) {});
op::submit([](g_t){});
// f on cpu - g on cpu (explicit: the first cpu task runs f and a second cpu
// f on cpu - g on cpu (explicit: the first cpu task runs f and a second cpu task runs g) // task runs g)
cpu | cpu | op::transform([](auto) { return f(); }) | op::via(mi::strands(cpu)) |
op::transform([](auto){ return f(); }) | op::transform([](f_t ft) { return g(ft); }) | op::submit([](g_t) {});
op::via(mi::strands(cpu)) |
op::transform([](f_t ft) {return g(ft);}) |
op::submit([](g_t){});
// f on io - g on cpu // f on io - g on cpu
io | io | op::transform([](auto) { return f(); }) | op::via(mi::strands(cpu)) |
op::transform([](auto){ return f(); }) | op::transform([](f_t ft) { return g(ft); }) | op::submit([](g_t) {});
op::via(mi::strands(cpu)) |
op::transform([](f_t ft) {return g(ft);}) |
op::submit([](g_t){});
} }
template<class CPUExecutor, class IOExecutor> template <class CPUExecutor, class IOExecutor>
void pipe(CPUExecutor cpu, IOExecutor io) { void pipe(CPUExecutor cpu, IOExecutor io) {
// f on cpu - g on cpu (implicit: a single task on the cpu executor runs all the functions) // f on cpu - g on cpu (implicit: a single task on the cpu executor runs all
// the functions)
mi::pipe( mi::pipe(
cpu, cpu,
op::transform([](auto){ return f(); }), op::transform([](auto) { return f(); }),
op::transform([](f_t ft) {return g(ft);}), op::transform([](f_t ft) { return g(ft); }),
op::submit([](g_t){})); op::submit([](g_t) {}));
// f on cpu - g on cpu (explicit: the first cpu task runs f and a second cpu task runs g) // f on cpu - g on cpu (explicit: the first cpu task runs f and a second cpu
// task runs g)
mi::pipe( mi::pipe(
cpu, cpu,
op::transform([](auto){ return f(); }), op::transform([](auto) { return f(); }),
op::via(mi::strands(cpu)), op::via(mi::strands(cpu)),
op::transform([](f_t ft) {return g(ft);}), op::transform([](f_t ft) { return g(ft); }),
op::submit([](g_t){})); op::submit([](g_t) {}));
// f on io - g on cpu // f on io - g on cpu
mi::pipe( mi::pipe(
io, io,
op::transform([](auto){ return f(); }), op::transform([](auto) { return f(); }),
op::via(mi::strands(cpu)), op::via(mi::strands(cpu)),
op::transform([](f_t ft) {return g(ft);}), op::transform([](f_t ft) { return g(ft); }),
op::submit([](g_t){})); op::submit([](g_t) {}));
} }
int main() int main() {
{ mi::pool cpuPool{std::max(1u, std::thread::hardware_concurrency())};
mi::pool cpuPool{std::max(1u,std::thread::hardware_concurrency())}; mi::pool ioPool{std::max(1u, std::thread::hardware_concurrency())};
mi::pool ioPool{std::max(1u,std::thread::hardware_concurrency())};
lisp(cpuPool.executor(), ioPool.executor()); lisp(cpuPool.executor(), ioPool.executor());
sugar(cpuPool.executor(), ioPool.executor()); sugar(cpuPool.executor(), ioPool.executor());
......
#include <vector> /*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <vector>
#include <folly/experimental/pushmi/o/defer.h> #include <folly/experimental/pushmi/o/defer.h>
#include <folly/experimental/pushmi/o/share.h> #include <folly/experimental/pushmi/o/share.h>
...@@ -20,52 +35,47 @@ using namespace pushmi::aliases; ...@@ -20,52 +35,47 @@ using namespace pushmi::aliases;
// this constructs eagerly and submits just() lazily // this constructs eagerly and submits just() lazily
auto defer_execution() { auto defer_execution() {
printf("construct just\n"); printf("construct just\n");
return op::just(42) | return op::just(42) | op::tap([](int v) { printf("just - %d\n", v); });
op::tap([](int v){ printf("just - %d\n", v); });
} }
// this constructs defer() eagerly, constructs just() and submits just() lazily // this constructs defer() eagerly, constructs just() and submits just() lazily
auto defer_construction() { auto defer_construction() {
return op::defer([]{ return op::defer([] { return defer_execution(); });
return defer_execution();
});
} }
// this constructs defer(), constructs just() and submits just() eagerly // this constructs defer(), constructs just() and submits just() eagerly
auto eager_execution() { auto eager_execution() {
return defer_execution() | op::share<int>(); return defer_execution() | op::share<int>();
} }
int main() int main() {
{
printf("\ncall defer_execution\n"); printf("\ncall defer_execution\n");
auto de = defer_execution(); auto de = defer_execution();
printf("submit defer_execution\n"); printf("submit defer_execution\n");
de | op::submit(); de | op::submit();
// call defer_execution // call defer_execution
// construct just // construct just
// submit defer_execution // submit defer_execution
// just - 42 // just - 42
printf("\ncall defer_construction\n"); printf("\ncall defer_construction\n");
auto dc = defer_construction(); auto dc = defer_construction();
printf("submit defer_construction\n"); printf("submit defer_construction\n");
dc | op::submit(); dc | op::submit();
// call defer_construction // call defer_construction
// submit defer_construction // submit defer_construction
// construct just // construct just
// just - 42 // just - 42
printf("\ncall eager_execution\n"); printf("\ncall eager_execution\n");
auto ee = eager_execution(); auto ee = eager_execution();
printf("submit eager_execution\n"); printf("submit eager_execution\n");
ee | op::submit(); ee | op::submit();
// call eager_execution // call eager_execution
// construct just // construct just
// just - 42 // just - 42
// submit eager_execution // submit eager_execution
std::cout << "OK" << std::endl; std::cout << "OK" << std::endl;
// OK // OK
} }
#include <vector> /*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <vector>
#include <folly/experimental/pushmi/examples/pool.h> #include <folly/experimental/pushmi/examples/pool.h>
...@@ -14,28 +29,26 @@ ...@@ -14,28 +29,26 @@
using namespace pushmi::aliases; using namespace pushmi::aliases;
template<class Io> template <class Io>
auto io_operation(Io io) { auto io_operation(Io io) {
return io | return io | op::transform([](auto) { return 42; }) |
op::transform([](auto){ return 42; }) | op::tap([](int v) { printf("io pool producing, %d\n", v); }) |
op::tap([](int v){ printf("io pool producing, %d\n", v); }) |
op::request_via(); op::request_via();
} }
int main() int main() {
{ mi::pool cpuPool{std::max(1u, std::thread::hardware_concurrency())};
mi::pool cpuPool{std::max(1u,std::thread::hardware_concurrency())}; mi::pool ioPool{std::max(1u, std::thread::hardware_concurrency())};
mi::pool ioPool{std::max(1u,std::thread::hardware_concurrency())};
auto io = ioPool.executor(); auto io = ioPool.executor();
auto cpu = cpuPool.executor(); auto cpu = cpuPool.executor();
io_operation(io).via(mi::strands(cpu)) | io_operation(io).via(mi::strands(cpu)) |
op::tap([](int v){ printf("cpu pool processing, %d\n", v); }) | op::tap([](int v) { printf("cpu pool processing, %d\n", v); }) |
op::submit(); op::submit();
// when the caller is not going to process the result (only side-effect matters) // when the caller is not going to process the result (only side-effect
// or the caller is just going to push the result into a queue. // matters) or the caller is just going to push the result into a queue.
// provide a way to skip the transition to a different executor and make it // provide a way to skip the transition to a different executor and make it
// stand out so that it has to be justified in code reviews. // stand out so that it has to be justified in code reviews.
mi::via_cast<mi::is_sender<>>(io_operation(io)) | op::submit(); mi::via_cast<mi::is_sender<>>(io_operation(io)) | op::submit();
......
#pragma once #pragma once
/*
// Copyright (c) 2018-present, Facebook, Inc. * Copyright 2018-present Facebook, Inc.
// *
// This source code is licensed under the MIT license found in the * Licensed under the Apache License, Version 2.0 (the "License");
// LICENSE file in the root directory of this source tree. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/examples/bulk.h> #include <folly/experimental/pushmi/examples/bulk.h>
#include <folly/experimental/pushmi/o/submit.h>
#include <folly/experimental/pushmi/o/just.h> #include <folly/experimental/pushmi/o/just.h>
#include <folly/experimental/pushmi/o/submit.h>
namespace pushmi { namespace pushmi {
PUSHMI_INLINE_VAR constexpr struct for_each_fn { PUSHMI_INLINE_VAR constexpr struct for_each_fn {
private: private:
template <class Function> template <class Function>
struct fn { struct fn {
Function f_; Function f_;
...@@ -23,29 +33,28 @@ private: ...@@ -23,29 +33,28 @@ private:
}; };
struct identity { struct identity {
template <class T> template <class T>
auto operator()(T&& t) const { return (T&&) t; } auto operator()(T&& t) const {
return (T &&) t;
}
}; };
struct zero { struct zero {
int operator()(detail::any) const noexcept { return 0; } int operator()(detail::any) const noexcept {
return 0;
}
}; };
public:
template<class ExecutionPolicy, class RandomAccessIterator, class Function> public:
template <class ExecutionPolicy, class RandomAccessIterator, class Function>
void operator()( void operator()(
ExecutionPolicy&& policy, ExecutionPolicy&& policy,
RandomAccessIterator begin, RandomAccessIterator begin,
RandomAccessIterator end, RandomAccessIterator end,
Function f) const { Function f) const {
operators::just(0) | operators::just(0) |
operators::bulk( operators::bulk(
fn<Function>{f}, fn<Function>{f}, begin, end, policy, identity{}, zero{}) |
begin, operators::blocking_submit();
end,
policy,
identity{},
zero{}
) |
operators::blocking_submit();
} }
} for_each {}; } for_each{};
} // namespace pushmi } // namespace pushmi
#include <vector> /*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <vector>
#include <folly/experimental/pushmi/examples/pool.h>
#include <folly/experimental/pushmi/examples/for_each.h> #include <folly/experimental/pushmi/examples/for_each.h>
#include <folly/experimental/pushmi/examples/pool.h>
using namespace pushmi::aliases; using namespace pushmi::aliases;
template<class Executor, class Allocator = std::allocator<char>> template <class Executor, class Allocator = std::allocator<char>>
auto naive_executor_bulk_target(Executor e, Allocator a = Allocator{}) { auto naive_executor_bulk_target(Executor e, Allocator a = Allocator{}) {
return [e, a]( return [e, a](
auto init, auto init,
auto selector, auto selector,
auto input, auto input,
auto&& func, auto&& func,
auto sb, auto sb,
auto se, auto se,
auto out) { auto out) {
using RS = decltype(selector); using RS = decltype(selector);
using F = std::conditional_t< using F = std::conditional_t<
std::is_lvalue_reference<decltype(func)>::value, std::is_lvalue_reference<decltype(func)>::value,
decltype(func), decltype(func),
typename std::remove_reference<decltype(func)>::type>; typename std::remove_reference<decltype(func)>::type>;
using Out = decltype(out); using Out = decltype(out);
try { try {
typename std::allocator_traits<Allocator>::template rebind_alloc<char> allocState(a); typename std::allocator_traits<Allocator>::template rebind_alloc<char>
auto shared_state = std::allocate_shared< allocState(a);
std::tuple< auto shared_state = std::allocate_shared<std::tuple<
std::exception_ptr, // first exception std::exception_ptr, // first exception
Out, // destination Out, // destination
RS, // selector RS, // selector
F, // func F, // func
std::atomic<decltype(init(input))>, // accumulation std::atomic<decltype(init(input))>, // accumulation
std::atomic<std::size_t>, // pending std::atomic<std::size_t>, // pending
std::atomic<std::size_t> // exception count (protects assignment to first exception) std::atomic<std::size_t> // exception count (protects assignment to
>>(allocState, std::exception_ptr{}, std::move(out), std::move(selector), (decltype(func) &&) func, init(std::move(input)), 1, 0); // first exception)
e | op::submit([e, sb, se, shared_state](auto){ >>(
auto stepDone = [](auto shared_state){ allocState,
// pending std::exception_ptr{},
if (--std::get<5>(*shared_state) == 0) { std::move(out),
// first exception std::move(selector),
if (std::get<0>(*shared_state)) { (decltype(func)&&)func,
mi::set_error(std::get<1>(*shared_state), std::get<0>(*shared_state)); init(std::move(input)),
return; 1,
} 0);
try { e | op::submit([e, sb, se, shared_state](auto) {
// selector(accumulation) auto stepDone = [](auto shared_state) {
auto result = std::get<2>(*shared_state)(std::move(std::get<4>(*shared_state).load())); // pending
mi::set_value(std::get<1>(*shared_state), std::move(result)); if (--std::get<5>(*shared_state) == 0) {
} catch(...) { // first exception
mi::set_error(std::get<1>(*shared_state), std::current_exception()); if (std::get<0>(*shared_state)) {
} mi::set_error(
} std::get<1>(*shared_state), std::get<0>(*shared_state));
}; return;
for (decltype(sb) idx{sb}; idx != se; ++idx, ++std::get<5>(*shared_state)){ }
e | op::submit([shared_state, idx, stepDone](auto ex){ try {
try { // selector(accumulation)
// this indicates to me that bulk is not the right abstraction auto result = std::get<2>(*shared_state)(
auto old = std::get<4>(*shared_state).load(); std::move(std::get<4>(*shared_state).load()));
auto step = old; mi::set_value(std::get<1>(*shared_state), std::move(result));
do { } catch (...) {
step = old; mi::set_error(
// func(accumulation, idx) std::get<1>(*shared_state), std::current_exception());
std::get<3>(*shared_state)(step, idx); }
} while(!std::get<4>(*shared_state).compare_exchange_strong(old, step)); }
} catch(...) { };
// exception count for (decltype(sb) idx{sb}; idx != se;
if (std::get<6>(*shared_state)++ == 0) { ++idx, ++std::get<5>(*shared_state)) {
// store first exception e | op::submit([shared_state, idx, stepDone](auto ex) {
std::get<0>(*shared_state) = std::current_exception(); try {
} // else eat the exception // this indicates to me that bulk is not the right abstraction
} auto old = std::get<4>(*shared_state).load();
stepDone(shared_state); auto step = old;
}); do {
step = old;
// func(accumulation, idx)
std::get<3> (*shared_state)(step, idx);
} while (!std::get<4>(*shared_state)
.compare_exchange_strong(old, step));
} catch (...) {
// exception count
if (std::get<6>(*shared_state)++ == 0) {
// store first exception
std::get<0>(*shared_state) = std::current_exception();
} // else eat the exception
} }
stepDone(shared_state); stepDone(shared_state);
}); });
} catch(...) {
e | op::submit([out = std::move(out), ep = std::current_exception()](auto) mutable {
mi::set_error(out, ep);
});
} }
}; stepDone(shared_state);
});
} catch (...) {
e |
op::submit([out = std::move(out), ep = std::current_exception()](
auto) mutable { mi::set_error(out, ep); });
}
};
} }
int main() int main() {
{ mi::pool p{std::max(1u, std::thread::hardware_concurrency())};
mi::pool p{std::max(1u,std::thread::hardware_concurrency())};
std::vector<int> vec(10); std::vector<int> vec(10);
mi::for_each(naive_executor_bulk_target(p.executor()), vec.begin(), vec.end(), [](int& x){ mi::for_each(
x = 42; naive_executor_bulk_target(p.executor()),
}); vec.begin(),
vec.end(),
[](int& x) { x = 42; });
assert(std::count(vec.begin(), vec.end(), 42) == static_cast<int>(vec.size())); assert(
std::count(vec.begin(), vec.end(), 42) == static_cast<int>(vec.size()));
std::cout << "OK" << std::endl; std::cout << "OK" << std::endl;
......
#include <vector> /*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <vector>
#include <folly/experimental/pushmi/examples/for_each.h> #include <folly/experimental/pushmi/examples/for_each.h>
using namespace pushmi::aliases; using namespace pushmi::aliases;
auto inline_bulk_target() { auto inline_bulk_target() {
return []( return [](auto init,
auto init, auto selector,
auto selector, auto input,
auto input, auto&& func,
auto&& func, auto sb,
auto sb, auto se,
auto se, auto out) {
auto out) { try {
try { auto acc = init(input);
auto acc = init(input); for (decltype(sb) idx{sb}; idx != se; ++idx) {
for (decltype(sb) idx{sb}; idx != se; ++idx){ func(acc, idx);
func(acc, idx); }
} auto result = selector(std::move(acc));
auto result = selector(std::move(acc)); mi::set_value(out, std::move(result));
mi::set_value(out, std::move(result)); } catch (...) {
} catch(...) { mi::set_error(out, std::current_exception());
mi::set_error(out, std::current_exception()); }
} };
};
} }
int main() int main() {
{
std::vector<int> vec(10); std::vector<int> vec(10);
mi::for_each(inline_bulk_target(), vec.begin(), vec.end(), [](int& x){ mi::for_each(
x = 42; inline_bulk_target(), vec.begin(), vec.end(), [](int& x) { x = 42; });
});
assert(std::count(vec.begin(), vec.end(), 42) == static_cast<int>(vec.size())); assert(
std::count(vec.begin(), vec.end(), 42) == static_cast<int>(vec.size()));
std::cout << "OK" << std::endl; std::cout << "OK" << std::endl;
} }
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/single_sender.h>
#include <folly/experimental/pushmi/o/submit.h> #include <folly/experimental/pushmi/o/submit.h>
#include <folly/experimental/pushmi/single_sender.h>
namespace pushmi { namespace pushmi {
namespace detail { namespace detail {
struct no_fail_fn { struct no_fail_fn {
private: private:
struct on_error_impl { struct on_error_impl {
[[noreturn]] [[noreturn]] void operator()(any, any) noexcept {
void operator()(any, any) noexcept {
std::abort(); std::abort();
} }
}; };
template <class In> template <class In>
struct out_impl { struct out_impl {
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out>) (requires Receiver<Out>)auto operator()(Out out) const {
auto operator()(Out out) const {
return ::pushmi::detail::receiver_from_fn<In>()( return ::pushmi::detail::receiver_from_fn<In>()(
std::move(out), std::move(out), ::pushmi::on_error(on_error_impl{}));
::pushmi::on_error(on_error_impl{})
);
} }
}; };
struct in_impl { struct in_impl {
PUSHMI_TEMPLATE(class In) PUSHMI_TEMPLATE(class In)
(requires Sender<In>) (requires Sender<In>)auto operator()(In in) const {
auto operator()(In in) const {
return ::pushmi::detail::sender_from( return ::pushmi::detail::sender_from(
std::move(in), std::move(in),
::pushmi::detail::submit_transform_out<In>(out_impl<In>{}) ::pushmi::detail::submit_transform_out<In>(out_impl<In>{}));
);
} }
}; };
public:
public:
auto operator()() const { auto operator()() const {
return in_impl{}; return in_impl{};
} }
......
#pragma once #pragma once
/*
// Copyright (c) 2018-present, Facebook, Inc. * Copyright 2018-present Facebook, Inc.
// *
// This source code is licensed under the MIT license found in the * Licensed under the Apache License, Version 2.0 (the "License");
// LICENSE file in the root directory of this source tree. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <experimental/thread_pool> // @manual #include <experimental/thread_pool> // @manual
#include <folly/experimental/pushmi/executor.h> #include <folly/experimental/pushmi/executor.h>
#include <folly/experimental/pushmi/trampoline.h>
#include <folly/experimental/pushmi/time_single_sender.h> #include <folly/experimental/pushmi/time_single_sender.h>
#include <folly/experimental/pushmi/trampoline.h>
#if __cpp_deduction_guides >= 201703 #if __cpp_deduction_guides >= 201703
#define MAKE(x) x MAKE_ #define MAKE(x) x MAKE_
#define MAKE_(...) {__VA_ARGS__} #define MAKE_(...) \
{ __VA_ARGS__ }
#else #else
#define MAKE(x) make_ ## x #define MAKE(x) make_##x
#endif #endif
namespace pushmi { namespace pushmi {
...@@ -23,17 +34,23 @@ namespace pushmi { ...@@ -23,17 +34,23 @@ namespace pushmi {
using std::experimental::static_thread_pool; using std::experimental::static_thread_pool;
namespace execution = std::experimental::execution; namespace execution = std::experimental::execution;
template<class Executor> template <class Executor>
struct pool_executor { struct pool_executor {
using properties = property_set<is_sender<>, is_executor<>, is_never_blocking<>, is_concurrent_sequence<>, is_single<>>; using properties = property_set<
is_sender<>,
is_executor<>,
is_never_blocking<>,
is_concurrent_sequence<>,
is_single<>>;
using e_t = Executor; using e_t = Executor;
e_t e; e_t e;
explicit pool_executor(e_t e) : e(std::move(e)) {} explicit pool_executor(e_t e) : e(std::move(e)) {}
auto executor() { return *this; } auto executor() {
return *this;
}
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out>) (requires Receiver<Out>)void submit(Out out) const {
void submit(Out out) const {
e.execute([e = *this, out = std::move(out)]() mutable { e.execute([e = *this, out = std::move(out)]() mutable {
::pushmi::set_value(out, e); ::pushmi::set_value(out, e);
}); });
...@@ -42,17 +59,22 @@ struct pool_executor { ...@@ -42,17 +59,22 @@ struct pool_executor {
class pool { class pool {
static_thread_pool p; static_thread_pool p;
public:
public:
inline explicit pool(std::size_t threads) : p(threads) {} inline explicit pool(std::size_t threads) : p(threads) {}
inline auto executor() { inline auto executor() {
auto exec = execution::require(p.executor(), execution::never_blocking, execution::oneway); auto exec = execution::require(
p.executor(), execution::never_blocking, execution::oneway);
return pool_executor<decltype(exec)>{exec}; return pool_executor<decltype(exec)>{exec};
} }
inline void stop() {p.stop();} inline void stop() {
inline void wait() {p.wait();} p.stop();
}
inline void wait() {
p.wait();
}
}; };
} // namespace pushmi } // namespace pushmi
#pragma once #pragma once
/*
// Copyright (c) 2018-present, Facebook, Inc. * Copyright 2018-present Facebook, Inc.
// *
// This source code is licensed under the MIT license found in the * Licensed under the Apache License, Version 2.0 (the "License");
// LICENSE file in the root directory of this source tree. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/examples/bulk.h> #include <folly/experimental/pushmi/examples/bulk.h>
#include <folly/experimental/pushmi/o/submit.h>
#include <folly/experimental/pushmi/o/just.h> #include <folly/experimental/pushmi/o/just.h>
#include <folly/experimental/pushmi/o/submit.h>
namespace pushmi { namespace pushmi {
PUSHMI_INLINE_VAR constexpr struct reduce_fn { PUSHMI_INLINE_VAR constexpr struct reduce_fn {
private: private:
template <class BinaryOp> template <class BinaryOp>
struct fn { struct fn {
BinaryOp binary_op_; BinaryOp binary_op_;
...@@ -24,28 +34,28 @@ private: ...@@ -24,28 +34,28 @@ private:
struct identity { struct identity {
template <class T> template <class T>
auto operator()(T&& t) const { auto operator()(T&& t) const {
return (T&&) t; return (T &&) t;
} }
}; };
public:
template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOp> public:
template <class ExecutionPolicy, class ForwardIt, class T, class BinaryOp>
T operator()( T operator()(
ExecutionPolicy&& policy, ExecutionPolicy&& policy,
ForwardIt begin, ForwardIt begin,
ForwardIt end, ForwardIt end,
T init, T init,
BinaryOp binary_op) const { BinaryOp binary_op) const {
return operators::just(std::move(init)) | return operators::just(std::move(init)) |
operators::bulk( operators::bulk(
fn<BinaryOp>{binary_op}, fn<BinaryOp>{binary_op},
begin, begin,
end, end,
policy, policy,
identity{}, identity{},
identity{} identity{}) |
) |
operators::get<T>; operators::get<T>;
} }
} reduce {}; } reduce{};
} // namespace pushmi } // namespace pushmi
#include <vector> /*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm> #include <algorithm>
#include <numeric>
#include <cassert> #include <cassert>
#include <iostream>
#include <exception> #include <exception>
#include <iostream>
#include <numeric>
#include <vector>
#include <folly/experimental/pushmi/examples/pool.h> #include <folly/experimental/pushmi/examples/pool.h>
#include <folly/experimental/pushmi/examples/reduce.h> #include <folly/experimental/pushmi/examples/reduce.h>
using namespace pushmi::aliases; using namespace pushmi::aliases;
template<class Executor, class Allocator = std::allocator<char>> template <class Executor, class Allocator = std::allocator<char>>
auto naive_executor_bulk_target(Executor e, Allocator a = Allocator{}) { auto naive_executor_bulk_target(Executor e, Allocator a = Allocator{}) {
return [e, a]( return [e, a](
auto init, auto init,
auto selector, auto selector,
auto input, auto input,
auto&& func, auto&& func,
auto sb, auto sb,
auto se, auto se,
auto out) { auto out) {
using RS = decltype(selector); using RS = decltype(selector);
using F = std::conditional_t< using F = std::conditional_t<
std::is_lvalue_reference<decltype(func)>::value, std::is_lvalue_reference<decltype(func)>::value,
decltype(func), decltype(func),
typename std::remove_reference<decltype(func)>::type>; typename std::remove_reference<decltype(func)>::type>;
using Out = decltype(out); using Out = decltype(out);
try { try {
typename std::allocator_traits<Allocator>::template rebind_alloc<char> allocState(a); typename std::allocator_traits<Allocator>::template rebind_alloc<char>
auto shared_state = std::allocate_shared< allocState(a);
std::tuple< auto shared_state = std::allocate_shared<std::tuple<
std::exception_ptr, // first exception std::exception_ptr, // first exception
Out, // destination Out, // destination
RS, // selector RS, // selector
F, // func F, // func
std::atomic<decltype(init(input))>, // accumulation std::atomic<decltype(init(input))>, // accumulation
std::atomic<std::size_t>, // pending std::atomic<std::size_t>, // pending
std::atomic<std::size_t> // exception count (protects assignment to first exception) std::atomic<std::size_t> // exception count (protects assignment to
>>(allocState, std::exception_ptr{}, std::move(out), std::move(selector), (decltype(func) &&) func, init(std::move(input)), 1, 0); // first exception)
e | op::submit([e, sb, se, shared_state](auto ){ >>(
auto stepDone = [](auto shared_state){ allocState,
// pending std::exception_ptr{},
if (--std::get<5>(*shared_state) == 0) { std::move(out),
// first exception std::move(selector),
if (std::get<0>(*shared_state)) { (decltype(func)&&)func,
mi::set_error(std::get<1>(*shared_state), std::get<0>(*shared_state)); init(std::move(input)),
return; 1,
} 0);
try { e | op::submit([e, sb, se, shared_state](auto) {
// selector(accumulation) auto stepDone = [](auto shared_state) {
auto result = std::get<2>(*shared_state)(std::move(std::get<4>(*shared_state).load())); // pending
mi::set_value(std::get<1>(*shared_state), std::move(result)); if (--std::get<5>(*shared_state) == 0) {
} catch(...) { // first exception
mi::set_error(std::get<1>(*shared_state), std::current_exception()); if (std::get<0>(*shared_state)) {
} mi::set_error(
} std::get<1>(*shared_state), std::get<0>(*shared_state));
}; return;
for (decltype(sb) idx{sb}; idx != se; ++idx, ++std::get<5>(*shared_state)){ }
e | op::submit([shared_state, idx, stepDone](auto ex){ try {
try { // selector(accumulation)
// this indicates to me that bulk is not the right abstraction auto result = std::get<2>(*shared_state)(
auto old = std::get<4>(*shared_state).load(); std::move(std::get<4>(*shared_state).load()));
auto step = old; mi::set_value(std::get<1>(*shared_state), std::move(result));
do { } catch (...) {
step = old; mi::set_error(
// func(accumulation, idx) std::get<1>(*shared_state), std::current_exception());
std::get<3>(*shared_state)(step, idx); }
} while(!std::get<4>(*shared_state).compare_exchange_strong(old, step)); }
} catch(...) { };
// exception count for (decltype(sb) idx{sb}; idx != se;
if (std::get<6>(*shared_state)++ == 0) { ++idx, ++std::get<5>(*shared_state)) {
// store first exception e | op::submit([shared_state, idx, stepDone](auto ex) {
std::get<0>(*shared_state) = std::current_exception(); try {
} // else eat the exception // this indicates to me that bulk is not the right abstraction
} auto old = std::get<4>(*shared_state).load();
stepDone(shared_state); auto step = old;
}); do {
step = old;
// func(accumulation, idx)
std::get<3> (*shared_state)(step, idx);
} while (!std::get<4>(*shared_state)
.compare_exchange_strong(old, step));
} catch (...) {
// exception count
if (std::get<6>(*shared_state)++ == 0) {
// store first exception
std::get<0>(*shared_state) = std::current_exception();
} // else eat the exception
} }
stepDone(shared_state); stepDone(shared_state);
}); });
} catch(...) {
e | op::submit([out = std::move(out), ep = std::current_exception()](auto) mutable {
mi::set_error(out, ep);
});
} }
}; stepDone(shared_state);
});
} catch (...) {
e |
op::submit([out = std::move(out), ep = std::current_exception()](
auto) mutable { mi::set_error(out, ep); });
}
};
} }
int main() int main() {
{ mi::pool p{std::max(1u, std::thread::hardware_concurrency())};
mi::pool p{std::max(1u,std::thread::hardware_concurrency())};
std::vector<int> vec(10); std::vector<int> vec(10);
std::fill(vec.begin(), vec.end(), 4); std::fill(vec.begin(), vec.end(), 4);
auto fortyTwo = mi::reduce(naive_executor_bulk_target(p.executor()), vec.begin(), vec.end(), 2, std::plus<>{}); auto fortyTwo = mi::reduce(
naive_executor_bulk_target(p.executor()),
vec.begin(),
vec.end(),
2,
std::plus<>{});
assert(std::accumulate(vec.begin(), vec.end(), 2) == fortyTwo); assert(std::accumulate(vec.begin(), vec.end(), 2) == fortyTwo);
......
#include <vector> /*
#include <numeric> * Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cassert> #include <cassert>
#include <iostream>
#include <exception> #include <exception>
#include <iostream>
#include <numeric>
#include <vector>
#include <folly/experimental/pushmi/examples/reduce.h> #include <folly/experimental/pushmi/examples/reduce.h>
using namespace pushmi::aliases; using namespace pushmi::aliases;
auto inline_bulk_target() { auto inline_bulk_target() {
return []( return [](auto init,
auto init, auto selector,
auto selector, auto input,
auto input, auto&& func,
auto&& func, auto sb,
auto sb, auto se,
auto se, auto out) {
auto out) { try {
try { auto acc = init(input);
auto acc = init(input); for (decltype(sb) idx{sb}; idx != se; ++idx) {
for (decltype(sb) idx{sb}; idx != se; ++idx){ func(acc, idx);
func(acc, idx); }
} auto result = selector(std::move(acc));
auto result = selector(std::move(acc)); mi::set_value(out, std::move(result));
mi::set_value(out, std::move(result)); } catch (...) {
} catch(...) { mi::set_error(out, std::current_exception());
mi::set_error(out, std::current_exception()); }
} };
};
} }
int main() int main() {
{
std::vector<int> vec(10); std::vector<int> vec(10);
std::fill(vec.begin(), vec.end(), 4); std::fill(vec.begin(), vec.end(), 4);
auto fortyTwo = mi::reduce(inline_bulk_target(), vec.begin(), vec.end(), 2, std::plus<>{}); auto fortyTwo = mi::reduce(
inline_bulk_target(), vec.begin(), vec.end(), 2, std::plus<>{});
assert(std::accumulate(vec.begin(), vec.end(), 2) == fortyTwo); assert(std::accumulate(vec.begin(), vec.end(), 2) == fortyTwo);
std::cout << fortyTwo << std::endl;
std::cout << "OK" << std::endl; std::cout << "OK" << std::endl;
} }
#include <vector> /*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <vector>
#include <folly/experimental/pushmi/o/empty.h>
#include <folly/experimental/pushmi/o/filter.h>
#include <folly/experimental/pushmi/o/just.h> #include <folly/experimental/pushmi/o/just.h>
#include <folly/experimental/pushmi/o/tap.h> #include <folly/experimental/pushmi/o/tap.h>
#include <folly/experimental/pushmi/o/filter.h>
#include <folly/experimental/pushmi/o/transform.h> #include <folly/experimental/pushmi/o/transform.h>
#include <folly/experimental/pushmi/o/empty.h>
using namespace pushmi::aliases; using namespace pushmi::aliases;
const bool setting_exists = false; const bool setting_exists = false;
auto get_setting() { auto get_setting() {
return mi::make_single_sender( return mi::make_single_sender([](auto out) {
[](auto out){ if (setting_exists) {
if(setting_exists) { op::just(42) | op::submit(out);
op::just(42) | op::submit(out); } else {
} else { op::empty<int>() | op::submit(out);
op::empty<int>() | op::submit(out);
}
} }
); });
} }
auto println = [](auto v){std::cout << v << std::endl;}; auto println = [](auto v) { std::cout << v << std::endl; };
// concat not yet implemented // concat not yet implemented
template<class T, class E = std::exception_ptr> template <class T, class E = std::exception_ptr>
auto concat = auto concat = [](auto in) {
[](auto in){ return mi::make_single_sender([in](auto out) mutable {
return mi::make_single_sender( ::pushmi::submit(in, mi::make_receiver(out, [](auto out, auto v) {
[in](auto out) mutable { ::pushmi::submit(v, mi::any_receiver<E, T>(out));
::pushmi::submit(in, mi::make_receiver(out, }));
[](auto out, auto v){ });
::pushmi::submit(v, mi::any_receiver<E, T>(out)); };
}));
});
};
int main() int main() {
{ get_setting() | op::transform([](int i) { return std::to_string(i); }) |
get_setting() | op::submit(println);
op::transform([](int i){ return std::to_string(i); }) |
op::submit(println);
op::just(42) | op::just(42) | op::filter([](int i) { return i < 42; }) |
op::filter([](int i){ return i < 42; }) | op::transform([](int i) { return std::to_string(i); }) |
op::transform([](int i){ return std::to_string(i); }) | op::submit(println);
op::submit(println);
op::just(42) | op::just(42) | op::transform([](int i) {
op::transform([](int i) { if (i < 42) {
if (i < 42) { return mi::any_single_sender<std::exception_ptr, std::string>{
return mi::any_single_sender<std::exception_ptr, std::string>{op::empty<std::string>()}; op::empty<std::string>()};
} }
return mi::any_single_sender<std::exception_ptr, std::string>{op::just(std::to_string(i))}; return mi::any_single_sender<std::exception_ptr, std::string>{
}) | op::just(std::to_string(i))};
concat<std::string> | }) | concat<std::string> |
op::submit(println); op::submit(println);
std::cout << "OK" << std::endl; std::cout << "OK" << std::endl;
......
#include <vector> /*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <vector>
#include <folly/experimental/pushmi/o/just.h> #include <folly/experimental/pushmi/examples/no_fail.h>
#include <folly/experimental/pushmi/o/error.h>
#include <folly/experimental/pushmi/o/empty.h> #include <folly/experimental/pushmi/o/empty.h>
#include <folly/experimental/pushmi/o/transform.h> #include <folly/experimental/pushmi/o/error.h>
#include <folly/experimental/pushmi/o/just.h>
#include <folly/experimental/pushmi/o/switch_on_error.h> #include <folly/experimental/pushmi/o/switch_on_error.h>
#include <folly/experimental/pushmi/examples/no_fail.h> #include <folly/experimental/pushmi/o/transform.h>
using namespace pushmi::aliases; using namespace pushmi::aliases;
// concat not yet implemented // concat not yet implemented
template<class T, class E = std::exception_ptr> template <class T, class E = std::exception_ptr>
auto concat = auto concat = [](auto in) {
[](auto in){ return mi::make_single_sender([in](auto out) mutable {
return mi::make_single_sender( ::pushmi::submit(in, mi::make_receiver(out, [](auto out, auto v) {
[in](auto out) mutable { ::pushmi::submit(v, mi::any_receiver<E, T>(out));
::pushmi::submit(in, mi::make_receiver(out, }));
[](auto out, auto v){ });
::pushmi::submit(v, mi::any_receiver<E, T>(out)); };
}));
}); int main() {
};
int main()
{
auto stop_abort = mi::on_error([](auto) noexcept {}); auto stop_abort = mi::on_error([](auto) noexcept {});
// support all error value types // support all error value types
op::error(std::exception_ptr{}) | op::error(std::exception_ptr{}) | op::submit(stop_abort);
op::submit(stop_abort);
op::error(std::errc::argument_list_too_long) | op::error(std::errc::argument_list_too_long) | op::submit(stop_abort);
op::submit(stop_abort);
// transform an error // transform an error
op::error(std::errc::argument_list_too_long) | op::error(std::errc::argument_list_too_long) | op::switch_on_error([
op::switch_on_error([](auto) noexcept { return op::error(std::exception_ptr{}); }) | ](auto) noexcept { return op::error(std::exception_ptr{}); }) |
op::submit(stop_abort); op::submit(stop_abort);
// use default value if an error occurs // use default value if an error occurs
op::just(42) | op::just(42) |
op::switch_on_error([](auto) noexcept { return op::just(0); }) | op::switch_on_error([](auto) noexcept { return op::just(0); }) |
op::submit(); op::submit();
// suppress if an error occurs // suppress if an error occurs
op::error(std::errc::argument_list_too_long) | op::error(std::errc::argument_list_too_long) |
op::switch_on_error([](auto) noexcept { return op::empty(); }) | op::switch_on_error([](auto) noexcept { return op::empty(); }) |
op::submit(); op::submit();
// abort if an error occurs // abort if an error occurs
op::just(42) | op::just(42) | op::no_fail() | op::submit();
op::no_fail() |
op::submit();
// transform value to error_ // transform value to error_
op::just(42) | op::just(42) | op::transform([](auto v) {
op::transform([](auto v) { using r_t = mi::any_single_sender<std::exception_ptr, int>;
using r_t = mi::any_single_sender<std::exception_ptr, int>; if (v < 40) {
if (v < 40) { return r_t{op::error<int>(std::exception_ptr{})};
return r_t{op::error<int>(std::exception_ptr{})}; } else {
} else { return r_t{op::just(v)};
return r_t{op::just(v)}; }
} }) | concat<int> |
}) | op::submit();
concat<int> |
op::submit(); // retry on error
// retry on error
// http.get(ex) | // http.get(ex) |
// op::timeout(ex, 1s) | // op::timeout(ex, 1s) |
......
#include <vector> /*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <vector>
#include <memory>
#include <utility>
#include <atomic>
#include <thread>
#include <functional>
#include <futures.h> #include <futures.h>
#include <futures_static_thread_pool.h> #include <futures_static_thread_pool.h>
#include <atomic>
#include <functional>
#include <memory>
#include <thread>
#include <utility>
#include <folly/experimental/pushmi/examples/pool.h> #include <folly/experimental/pushmi/examples/pool.h>
#include <folly/experimental/pushmi/strand.h>
#include <folly/experimental/pushmi/o/just.h> #include <folly/experimental/pushmi/o/just.h>
#include <folly/experimental/pushmi/o/via.h>
#include <folly/experimental/pushmi/o/transform.h> #include <folly/experimental/pushmi/o/transform.h>
#include <folly/experimental/pushmi/o/via.h>
#include <folly/experimental/pushmi/strand.h>
using namespace pushmi::aliases; using namespace pushmi::aliases;
struct inline_executor struct inline_executor {
{ public:
public:
friend bool operator==( friend bool operator==(
const inline_executor&, const inline_executor&) noexcept { return true; } const inline_executor&,
const inline_executor&) noexcept {
return true;
}
friend bool operator!=( friend bool operator!=(
const inline_executor&, const inline_executor&) noexcept { return false; } const inline_executor&,
template<class Function> const inline_executor&) noexcept {
void execute(Function f) const noexcept { f(); } return false;
constexpr bool query(std::experimental::execution::oneway_t) { return true; } }
constexpr bool query(std::experimental::execution::twoway_t) { return false; } template <class Function>
constexpr bool query(std::experimental::execution::single_t) { return true; } void execute(Function f) const noexcept {
f();
}
constexpr bool query(std::experimental::execution::oneway_t) {
return true;
}
constexpr bool query(std::experimental::execution::twoway_t) {
return false;
}
constexpr bool query(std::experimental::execution::single_t) {
return true;
}
}; };
namespace p1054 { namespace p1054 {
...@@ -43,57 +71,61 @@ namespace p1054 { ...@@ -43,57 +71,61 @@ namespace p1054 {
// the promise has to exist prior to .then() getting a continuation. // the promise has to exist prior to .then() getting a continuation.
// there must be a shared allocation to connect the promise and future. // there must be a shared allocation to connect the promise and future.
template <class T, class Executor> template <class T, class Executor>
std::pair<std::experimental::standard_promise<T>, std::experimental::standard_future<T, std::decay_t<Executor>>> std::pair<
std::experimental::standard_promise<T>,
std::experimental::standard_future<T, std::decay_t<Executor>>>
make_promise_contract(const Executor& e) { make_promise_contract(const Executor& e) {
std::experimental::standard_promise<T> promise; std::experimental::standard_promise<T> promise;
auto ex = e; auto ex = e;
return {promise, promise.get_future(std::move(ex))}; return {promise, promise.get_future(std::move(ex))};
} }
template<class Executor, class Function, class Future> template <class Executor, class Function, class Future>
std::experimental::standard_future< std::experimental::standard_future<
std::result_of_t<Function(std::decay_t<typename std::decay_t<Future>::value_type>&&)>, std::decay_t<Executor>> std::result_of_t<
then_execute(Executor&& e, Function&& f, Future&& pred) { Function(std::decay_t<typename std::decay_t<Future>::value_type>&&)>,
using V = std::decay_t<typename std::decay_t<Future>::value_type>; std::decay_t<Executor>>
using T = std::result_of_t<Function(V&&)>; then_execute(Executor&& e, Function&& f, Future&& pred) {
auto pc = make_promise_contract<T>(e); using V = std::decay_t<typename std::decay_t<Future>::value_type>;
auto p = std::get<0>(pc); using T = std::result_of_t<Function(V &&)>;
auto r = std::get<1>(pc); auto pc = make_promise_contract<T>(e);
((Future&&)pred).then([e, p, f](V v) mutable { auto p = std::get<0>(pc);
e.execute([p, f, v]() mutable { auto r = std::get<1>(pc);
p.set_value(f(v)); ((Future &&) pred).then([e, p, f](V v) mutable {
}); e.execute([p, f, v]() mutable { p.set_value(f(v)); });
return 0; return 0;
}); });
return r; return r;
}
} }
} // namespace p1054
namespace p1055 { namespace p1055 {
template<class Executor, class Function, class Future> template <class Executor, class Function, class Future>
auto then_execute(Executor&& e, Function&& f, Future&& pred) { auto then_execute(Executor&& e, Function&& f, Future&& pred) {
return pred | op::via(mi::strands(e)) | op::transform([f](auto v){return f(v);}); return pred | op::via(mi::strands(e)) |
op::transform([f](auto v) { return f(v); });
} }
} // namespace p1055
} int main() {
mi::pool p{std::max(1u, std::thread::hardware_concurrency())};
int main()
{
mi::pool p{std::max(1u,std::thread::hardware_concurrency())};
std::experimental::futures_static_thread_pool sp{std::max(1u,std::thread::hardware_concurrency())}; std::experimental::futures_static_thread_pool sp{
std::max(1u, std::thread::hardware_concurrency())};
auto pc = p1054::make_promise_contract<int>(inline_executor{}); auto pc = p1054::make_promise_contract<int>(inline_executor{});
auto& pr = std::get<0>(pc); auto& pr = std::get<0>(pc);
auto& r = std::get<1>(pc); auto& r = std::get<1>(pc);
auto f = p1054::then_execute(sp.executor(), [](int v){return v*2;}, std::move(r)); auto f = p1054::then_execute(
sp.executor(), [](int v) { return v * 2; }, std::move(r));
pr.set_value(42); pr.set_value(42);
f.get(); f.get();
p1055::then_execute(p.executor(), [](int v){return v*2;}, op::just(21)) | op::get<int>; p1055::then_execute(p.executor(), [](int v) { return v * 2; }, op::just(21)) |
op::get<int>;
sp.stop(); sp.stop();
sp.wait(); sp.wait();
......
#include <vector> /*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <vector>
#include <memory> #include <futures.h>
#include <utility>
#include <atomic> #include <atomic>
#include <thread>
#include <functional> #include <functional>
#include <futures.h> #include <memory>
#include <thread>
#include <utility>
#include <folly/experimental/pushmi/examples/pool.h> #include <folly/experimental/pushmi/examples/pool.h>
...@@ -25,43 +40,47 @@ namespace p1054 { ...@@ -25,43 +40,47 @@ namespace p1054 {
// the promise has to exist prior to .then() getting a continuation. // the promise has to exist prior to .then() getting a continuation.
// there must be a shared allocation to connect the promise and future. // there must be a shared allocation to connect the promise and future.
template <class T, class Executor> template <class T, class Executor>
std::pair<std::experimental::standard_promise<T>, std::experimental::standard_future<T, std::decay_t<Executor>>> std::pair<
std::experimental::standard_promise<T>,
std::experimental::standard_future<T, std::decay_t<Executor>>>
make_promise_contract(const Executor& e) { make_promise_contract(const Executor& e) {
std::experimental::standard_promise<T> promise; std::experimental::standard_promise<T> promise;
auto ex = e; auto ex = e;
return {promise, promise.get_future(std::move(ex))}; return {promise, promise.get_future(std::move(ex))};
} }
template<class Executor, class Function> template <class Executor, class Function>
std::experimental::standard_future<std::result_of_t<std::decay_t<Function>()>, std::decay_t<Executor>> std::experimental::standard_future<
twoway_execute(Executor&& e, Function&& f) { std::result_of_t<std::decay_t<Function>()>,
using T = std::result_of_t<std::decay_t<Function>()>; std::decay_t<Executor>>
auto pc = make_promise_contract<T>(e); twoway_execute(Executor&& e, Function&& f) {
auto p = std::get<0>(pc); using T = std::result_of_t<std::decay_t<Function>()>;
auto r = std::get<1>(pc); auto pc = make_promise_contract<T>(e);
e.execute([p, f]() mutable {p.set_value(f());}); auto p = std::get<0>(pc);
return r; auto r = std::get<1>(pc);
} e.execute([p, f]() mutable { p.set_value(f()); });
return r;
} }
} // namespace p1054
namespace p1055 { namespace p1055 {
template<class Executor, class Function> template <class Executor, class Function>
auto twoway_execute(Executor&& e, Function&& f) { auto twoway_execute(Executor&& e, Function&& f) {
return e | op::transform([f](auto){return f();}); return e | op::transform([f](auto) { return f(); });
} }
} } // namespace p1055
int main() int main() {
{ mi::pool p{std::max(1u, std::thread::hardware_concurrency())};
mi::pool p{std::max(1u,std::thread::hardware_concurrency())};
std::experimental::static_thread_pool sp{std::max(1u,std::thread::hardware_concurrency())}; std::experimental::static_thread_pool sp{
std::max(1u, std::thread::hardware_concurrency())};
p1054::twoway_execute(sp.executor(), [](){return 42;}).get(); p1054::twoway_execute(sp.executor(), []() { return 42; }).get();
p1055::twoway_execute(p.executor(), [](){return 42;}) | op::get<int>; p1055::twoway_execute(p.executor(), []() { return 42; }) | op::get<int>;
sp.stop(); sp.stop();
sp.wait(); sp.wait();
......
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <chrono> #include <chrono>
#include <functional> #include <functional>
......
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <future> #include <future>
#include <functional> #include <functional>
#include <folly/experimental/pushmi/traits.h> #include <folly/experimental/pushmi/forwards.h>
#include <folly/experimental/pushmi/properties.h> #include <folly/experimental/pushmi/properties.h>
#include <folly/experimental/pushmi/traits.h>
namespace pushmi { namespace pushmi {
namespace __adl { namespace __adl {
...@@ -349,7 +361,8 @@ PUSHMI_INLINE_VAR constexpr __adl::get_top_fn now{}; ...@@ -349,7 +361,8 @@ PUSHMI_INLINE_VAR constexpr __adl::get_top_fn now{};
PUSHMI_INLINE_VAR constexpr __adl::get_top_fn top{}; PUSHMI_INLINE_VAR constexpr __adl::get_top_fn top{};
template<class T> template<class T>
struct property_set_traits<T, std::enable_if_t<(bool)Invocable<T&> && not Valid<T&, __properties_t>>> { struct property_set_traits<T, std::enable_if_t<(bool)Invocable<T&> &&
not Valid<T&, __properties_t>>> {
using properties = property_set<is_receiver<>>; using properties = property_set<is_receiver<>>;
}; };
......
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/flow_receiver.h> #include <folly/experimental/pushmi/flow_receiver.h>
#include <folly/experimental/pushmi/executor.h> #include <folly/experimental/pushmi/executor.h>
......
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/receiver.h> #include <folly/experimental/pushmi/receiver.h>
......
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/flow_receiver.h> #include <folly/experimental/pushmi/flow_receiver.h>
#include <folly/experimental/pushmi/executor.h> #include <folly/experimental/pushmi/executor.h>
...@@ -27,12 +38,14 @@ class any_flow_single_sender { ...@@ -27,12 +38,14 @@ class any_flow_single_sender {
static void s_submit(data&, any_flow_receiver<PE, std::ptrdiff_t, E, VN...>) {} static void s_submit(data&, any_flow_receiver<PE, std::ptrdiff_t, E, VN...>) {}
void (*op_)(data&, data*) = vtable::s_op; void (*op_)(data&, data*) = vtable::s_op;
any_executor<E> (*executor_)(data&) = vtable::s_executor; any_executor<E> (*executor_)(data&) = vtable::s_executor;
void (*submit_)(data&, any_flow_receiver<PE, std::ptrdiff_t, E, VN...>) = vtable::s_submit; void (*submit_)(data&, any_flow_receiver<PE, std::ptrdiff_t, E, VN...>) =
vtable::s_submit;
}; };
static constexpr vtable const noop_ {}; static constexpr vtable const noop_ {};
vtable const* vptr_ = &noop_; vtable const* vptr_ = &noop_;
template <class Wrapped> template <class Wrapped>
any_flow_single_sender(Wrapped obj, std::false_type) : any_flow_single_sender() { any_flow_single_sender(Wrapped obj, std::false_type)
: any_flow_single_sender() {
struct s { struct s {
static void op(data& src, data* dst) { static void op(data& src, data* dst) {
if (dst) if (dst)
...@@ -40,9 +53,12 @@ class any_flow_single_sender { ...@@ -40,9 +53,12 @@ class any_flow_single_sender {
delete static_cast<Wrapped const*>(src.pobj_); delete static_cast<Wrapped const*>(src.pobj_);
} }
static any_executor<E> executor(data& src) { static any_executor<E> executor(data& src) {
return any_executor<E>{::pushmi::executor(*static_cast<Wrapped*>(src.pobj_))}; return any_executor<E>{
::pushmi::executor(*static_cast<Wrapped*>(src.pobj_))};
} }
static void submit(data& src, any_flow_receiver<PE, std::ptrdiff_t, E, VN...> out) { static void submit(
data& src,
any_flow_receiver<PE, std::ptrdiff_t, E, VN...> out) {
::pushmi::submit(*static_cast<Wrapped*>(src.pobj_), std::move(out)); ::pushmi::submit(*static_cast<Wrapped*>(src.pobj_), std::move(out));
} }
}; };
...@@ -56,17 +72,19 @@ class any_flow_single_sender { ...@@ -56,17 +72,19 @@ class any_flow_single_sender {
struct s { struct s {
static void op(data& src, data* dst) { static void op(data& src, data* dst) {
if (dst) if (dst)
new (dst->buffer_) Wrapped( new (dst->buffer_)
std::move(*static_cast<Wrapped*>((void*)src.buffer_))); Wrapped(std::move(*static_cast<Wrapped*>((void*)src.buffer_)));
static_cast<Wrapped const*>((void*)src.buffer_)->~Wrapped(); static_cast<Wrapped const*>((void*)src.buffer_)->~Wrapped();
} }
static any_executor<E> executor(data& src) { static any_executor<E> executor(data& src) {
return any_executor<E>{::pushmi::executor(*static_cast<Wrapped*>((void*)src.buffer_))}; return any_executor<E>{
::pushmi::executor(*static_cast<Wrapped*>((void*)src.buffer_))};
} }
static void submit(data& src, any_flow_receiver<PE, std::ptrdiff_t, E, VN...> out) { static void submit(
data& src,
any_flow_receiver<PE, std::ptrdiff_t, E, VN...> out) {
::pushmi::submit( ::pushmi::submit(
*static_cast<Wrapped*>((void*)src.buffer_), *static_cast<Wrapped*>((void*)src.buffer_), std::move(out));
std::move(out));
} }
}; };
static const vtable vtbl{s::op, s::executor, s::submit}; static const vtable vtbl{s::op, s::executor, s::submit};
...@@ -132,14 +150,19 @@ class flow_single_sender<SF, EXF> { ...@@ -132,14 +150,19 @@ class flow_single_sender<SF, EXF> {
} }
}; };
template <PUSHMI_TYPE_CONSTRAINT(Sender<is_single<>, is_flow<>>) Data, class DSF, class DEXF> template <
PUSHMI_TYPE_CONSTRAINT(Sender<is_single<>, is_flow<>>) Data,
class DSF,
class DEXF>
class flow_single_sender<Data, DSF, DEXF> { class flow_single_sender<Data, DSF, DEXF> {
Data data_; Data data_;
DSF sf_; DSF sf_;
DEXF exf_; DEXF exf_;
public: public:
using properties = property_set_insert_t<properties_t<Data>, property_set<is_sender<>, is_flow<>, is_single<>>>; using properties = property_set_insert_t<
properties_t<Data>,
property_set<is_sender<>, is_flow<>, is_single<>>>;
constexpr flow_single_sender() = default; constexpr flow_single_sender() = default;
constexpr explicit flow_single_sender(Data data) constexpr explicit flow_single_sender(Data data)
...@@ -177,7 +200,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_single_sender_fn { ...@@ -177,7 +200,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_single_sender_fn {
return flow_single_sender<SF, trampolineEXF>{std::move(sf)}; return flow_single_sender<SF, trampolineEXF>{std::move(sf)};
} }
PUSHMI_TEMPLATE(class SF, class EXF) PUSHMI_TEMPLATE(class SF, class EXF)
(requires True<> && Invocable<EXF&> PUSHMI_BROKEN_SUBSUMPTION(&& not Sender<SF>)) (requires True<> && Invocable<EXF&>
PUSHMI_BROKEN_SUBSUMPTION(&& not Sender<SF>))
auto operator()(SF sf, EXF exf) const { auto operator()(SF sf, EXF exf) const {
return flow_single_sender<SF, EXF>{std::move(sf), std::move(exf)}; return flow_single_sender<SF, EXF>{std::move(sf), std::move(exf)};
} }
...@@ -194,7 +218,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_single_sender_fn { ...@@ -194,7 +218,8 @@ PUSHMI_INLINE_VAR constexpr struct make_flow_single_sender_fn {
PUSHMI_TEMPLATE(class Data, class DSF, class DEXF) PUSHMI_TEMPLATE(class Data, class DSF, class DEXF)
(requires Sender<Data, is_single<>, is_flow<>> && Invocable<DEXF&, Data&>) (requires Sender<Data, is_single<>, is_flow<>> && Invocable<DEXF&, Data&>)
auto operator()(Data d, DSF sf, DEXF exf) const { auto operator()(Data d, DSF sf, DEXF exf) const {
return flow_single_sender<Data, DSF, DEXF>{std::move(d), std::move(sf), std::move(exf)}; return flow_single_sender<Data, DSF, DEXF>{std::move(d),
std::move(sf), std::move(exf)};
} }
} const make_flow_single_sender {}; } const make_flow_single_sender {};
...@@ -208,7 +233,8 @@ PUSHMI_TEMPLATE(class SF) ...@@ -208,7 +233,8 @@ PUSHMI_TEMPLATE(class SF)
flow_single_sender(SF) -> flow_single_sender<SF, trampolineEXF>; flow_single_sender(SF) -> flow_single_sender<SF, trampolineEXF>;
PUSHMI_TEMPLATE(class SF, class EXF) PUSHMI_TEMPLATE(class SF, class EXF)
(requires True<> && Invocable<EXF&> PUSHMI_BROKEN_SUBSUMPTION(&& not Sender<SF>)) (requires True<> && Invocable<EXF&>
PUSHMI_BROKEN_SUBSUMPTION(&& not Sender<SF>))
flow_single_sender(SF, EXF) -> flow_single_sender<SF, EXF>; flow_single_sender(SF, EXF) -> flow_single_sender<SF, EXF>;
PUSHMI_TEMPLATE(class Data) PUSHMI_TEMPLATE(class Data)
......
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <exception>
#include <chrono>
#include <folly/experimental/pushmi/traits.h> #include <folly/experimental/pushmi/traits.h>
#include <chrono>
#include <exception>
namespace pushmi { namespace pushmi {
...@@ -18,45 +29,45 @@ struct property_traits; ...@@ -18,45 +29,45 @@ struct property_traits;
template <class T, class = void> template <class T, class = void>
struct property_set_traits; struct property_set_traits;
template<class... PropertyN> template <class... PropertyN>
struct property_set; struct property_set;
// trait & tag types // trait & tag types
template<class...TN> template <class... TN>
struct is_single; struct is_single;
template<class...TN> template <class... TN>
struct is_many; struct is_many;
template<class...TN> template <class... TN>
struct is_flow; struct is_flow;
template<class...TN> template <class... TN>
struct is_receiver; struct is_receiver;
template<class...TN> template <class... TN>
struct is_sender; struct is_sender;
template<class... TN> template <class... TN>
struct is_executor; struct is_executor;
template<class...TN> template <class... TN>
struct is_time; struct is_time;
template<class...TN> template <class... TN>
struct is_constrained; struct is_constrained;
template<class... TN> template <class... TN>
struct is_always_blocking; struct is_always_blocking;
template<class... TN> template <class... TN>
struct is_never_blocking; struct is_never_blocking;
template<class... TN> template <class... TN>
struct is_maybe_blocking; struct is_maybe_blocking;
template<class... TN> template <class... TN>
struct is_fifo_sequence; struct is_fifo_sequence;
template<class... TN> template <class... TN>
struct is_concurrent_sequence; struct is_concurrent_sequence;
// implementation types // implementation types
...@@ -85,95 +96,77 @@ class flow_single_sender; ...@@ -85,95 +96,77 @@ class flow_single_sender;
template <PUSHMI_TYPE_CONSTRAINT(SemiMovable)... TN> template <PUSHMI_TYPE_CONSTRAINT(SemiMovable)... TN>
class flow_many_sender; class flow_many_sender;
template < template <class E = std::exception_ptr, class... VN>
class E = std::exception_ptr,
class... VN>
class any_receiver; class any_receiver;
template < template <
class PE=std::exception_ptr, class PE = std::exception_ptr,
class PV=std::ptrdiff_t, class PV = std::ptrdiff_t,
class E=PE, class E = PE,
class... VN> class... VN>
class any_flow_receiver; class any_flow_receiver;
template< template <class E = std::exception_ptr, class... VN>
class E = std::exception_ptr,
class... VN>
class any_single_sender; class any_single_sender;
template< template <class E = std::exception_ptr, class... VN>
class E = std::exception_ptr,
class... VN>
class any_many_sender; class any_many_sender;
template < template <class PE = std::exception_ptr, class E = PE, class... VN>
class PE=std::exception_ptr,
class E=PE,
class... VN>
class any_flow_single_sender; class any_flow_single_sender;
template < template <
class PE=std::exception_ptr, class PE = std::exception_ptr,
class PV=std::ptrdiff_t, class PV = std::ptrdiff_t,
class E=PE, class E = PE,
class... VN> class... VN>
class any_flow_many_sender; class any_flow_many_sender;
template< template <class E = std::exception_ptr, class C = std::ptrdiff_t, class... VN>
class E = std::exception_ptr,
class C = std::ptrdiff_t,
class... VN>
class any_constrained_single_sender; class any_constrained_single_sender;
template< template <
class E = std::exception_ptr, class E = std::exception_ptr,
class TP = std::chrono::system_clock::time_point, class TP = std::chrono::system_clock::time_point,
class... VN> class... VN>
class any_time_single_sender; class any_time_single_sender;
template< template <class E = std::exception_ptr>
class E = std::exception_ptr>
struct any_executor; struct any_executor;
template< template <class E = std::exception_ptr>
class E = std::exception_ptr>
struct any_executor_ref; struct any_executor_ref;
template< template <class E = std::exception_ptr, class CV = std::ptrdiff_t>
class E = std::exception_ptr,
class CV = std::ptrdiff_t>
struct any_constrained_executor; struct any_constrained_executor;
template< template <class E = std::exception_ptr, class TP = std::ptrdiff_t>
class E = std::exception_ptr,
class TP = std::ptrdiff_t>
struct any_constrained_executor_ref; struct any_constrained_executor_ref;
template< template <
class E = std::exception_ptr, class E = std::exception_ptr,
class TP = std::chrono::system_clock::time_point> class TP = std::chrono::system_clock::time_point>
struct any_time_executor; struct any_time_executor;
template< template <
class E = std::exception_ptr, class E = std::exception_ptr,
class TP = std::chrono::system_clock::time_point> class TP = std::chrono::system_clock::time_point>
struct any_time_executor_ref; struct any_time_executor_ref;
namespace operators {} namespace operators {}
namespace extension_operators {} namespace extension_operators {}
namespace aliases { namespace aliases {
namespace v = ::pushmi; namespace v = ::pushmi;
namespace mi = ::pushmi; namespace mi = ::pushmi;
namespace op = ::pushmi::operators; namespace op = ::pushmi::operators;
namespace ep = ::pushmi::extension_operators; namespace ep = ::pushmi::extension_operators;
} } // namespace aliases
namespace detail { namespace detail {
struct any { struct any {
template <class T> template <class T>
constexpr any(T&&) noexcept {} constexpr any(T&&) noexcept {}
}; };
} } // namespace detail
} // namespace pushmi } // namespace pushmi
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/executor.h> #include <folly/experimental/pushmi/executor.h>
namespace pushmi { namespace pushmi {
class inline_constrained_executor_t { class inline_constrained_executor_t {
public: public:
using properties = property_set<is_constrained<>, is_executor<>, is_always_blocking<>, is_fifo_sequence<>, is_single<>>; using properties = property_set<
is_constrained<>,
is_executor<>,
is_always_blocking<>,
is_fifo_sequence<>,
is_single<>>;
std::ptrdiff_t top() { std::ptrdiff_t top() {
return 0; return 0;
} }
auto executor() { return *this; } auto executor() {
PUSHMI_TEMPLATE(class CV, class Out) return *this;
(requires Regular<CV> && Receiver<Out>) }
void submit(CV, Out out) { PUSHMI_TEMPLATE(class CV, class Out)
::pushmi::set_value(out, *this); (requires Regular<CV>&& Receiver<Out>)void submit(CV, Out out) {
::pushmi::set_done(out); ::pushmi::set_value(out, *this);
} ::pushmi::set_done(out);
}
}; };
struct inlineConstrainedEXF { struct inlineConstrainedEXF {
inline_constrained_executor_t operator()(){ inline_constrained_executor_t operator()() {
return {}; return {};
} }
}; };
...@@ -35,24 +52,30 @@ inline inline_constrained_executor_t inline_constrained_executor() { ...@@ -35,24 +52,30 @@ inline inline_constrained_executor_t inline_constrained_executor() {
} }
class inline_time_executor_t { class inline_time_executor_t {
public: public:
using properties = property_set<is_time<>, is_executor<>, is_always_blocking<>, is_fifo_sequence<>, is_single<>>; using properties = property_set<
is_time<>,
is_executor<>,
is_always_blocking<>,
is_fifo_sequence<>,
is_single<>>;
auto top() { auto top() {
return std::chrono::system_clock::now(); return std::chrono::system_clock::now();
} }
auto executor() { return *this; } auto executor() {
PUSHMI_TEMPLATE(class TP, class Out) return *this;
(requires Regular<TP> && Receiver<Out>) }
void submit(TP tp, Out out) { PUSHMI_TEMPLATE(class TP, class Out)
std::this_thread::sleep_until(tp); (requires Regular<TP>&& Receiver<Out>)void submit(TP tp, Out out) {
::pushmi::set_value(out, *this); std::this_thread::sleep_until(tp);
::pushmi::set_done(out); ::pushmi::set_value(out, *this);
} ::pushmi::set_done(out);
}
}; };
struct inlineTimeEXF { struct inlineTimeEXF {
inline_time_executor_t operator()(){ inline_time_executor_t operator()() {
return {}; return {};
} }
}; };
...@@ -62,20 +85,26 @@ inline inline_time_executor_t inline_time_executor() { ...@@ -62,20 +85,26 @@ inline inline_time_executor_t inline_time_executor() {
} }
class inline_executor_t { class inline_executor_t {
public: public:
using properties = property_set<is_sender<>, is_executor<>, is_always_blocking<>, is_fifo_sequence<>, is_single<>>; using properties = property_set<
is_sender<>,
is_executor<>,
is_always_blocking<>,
is_fifo_sequence<>,
is_single<>>;
auto executor() { return *this; } auto executor() {
PUSHMI_TEMPLATE(class Out) return *this;
(requires Receiver<Out>) }
void submit(Out out) { PUSHMI_TEMPLATE(class Out)
::pushmi::set_value(out, *this); (requires Receiver<Out>)void submit(Out out) {
::pushmi::set_done(out); ::pushmi::set_value(out, *this);
} ::pushmi::set_done(out);
}
}; };
struct inlineEXF { struct inlineEXF {
inline_executor_t operator()(){ inline_executor_t operator()() {
return {}; return {};
} }
}; };
......
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/receiver.h>
#include <folly/experimental/pushmi/executor.h> #include <folly/experimental/pushmi/executor.h>
#include <folly/experimental/pushmi/receiver.h>
#include <folly/experimental/pushmi/trampoline.h> #include <folly/experimental/pushmi/trampoline.h>
namespace pushmi { namespace pushmi {
...@@ -23,13 +34,15 @@ class any_many_sender { ...@@ -23,13 +34,15 @@ class any_many_sender {
} }
struct vtable { struct vtable {
static void s_op(data&, data*) {} static void s_op(data&, data*) {}
static any_executor<E> s_executor(data&) { return {}; } static any_executor<E> s_executor(data&) {
return {};
}
static void s_submit(data&, any_receiver<E, VN...>) {} static void s_submit(data&, any_receiver<E, VN...>) {}
void (*op_)(data&, data*) = vtable::s_op; void (*op_)(data&, data*) = vtable::s_op;
any_executor<E> (*executor_)(data&) = vtable::s_executor; any_executor<E> (*executor_)(data&) = vtable::s_executor;
void (*submit_)(data&, any_receiver<E, VN...>) = vtable::s_submit; void (*submit_)(data&, any_receiver<E, VN...>) = vtable::s_submit;
}; };
static constexpr vtable const noop_ {}; static constexpr vtable const noop_{};
vtable const* vptr_ = &noop_; vtable const* vptr_ = &noop_;
template <class Wrapped> template <class Wrapped>
any_many_sender(Wrapped obj, std::false_type) : any_many_sender() { any_many_sender(Wrapped obj, std::false_type) : any_many_sender() {
...@@ -40,7 +53,8 @@ class any_many_sender { ...@@ -40,7 +53,8 @@ class any_many_sender {
delete static_cast<Wrapped const*>(src.pobj_); delete static_cast<Wrapped const*>(src.pobj_);
} }
static any_executor<E> executor(data& src) { static any_executor<E> executor(data& src) {
return any_executor<E>{::pushmi::executor(*static_cast<Wrapped*>(src.pobj_))}; return any_executor<E>{
::pushmi::executor(*static_cast<Wrapped*>(src.pobj_))};
} }
static void submit(data& src, any_receiver<E, VN...> out) { static void submit(data& src, any_receiver<E, VN...> out) {
::pushmi::submit(*static_cast<Wrapped*>(src.pobj_), std::move(out)); ::pushmi::submit(*static_cast<Wrapped*>(src.pobj_), std::move(out));
...@@ -51,17 +65,17 @@ class any_many_sender { ...@@ -51,17 +65,17 @@ class any_many_sender {
vptr_ = &vtbl; vptr_ = &vtbl;
} }
template <class Wrapped> template <class Wrapped>
any_many_sender(Wrapped obj, std::true_type) noexcept any_many_sender(Wrapped obj, std::true_type) noexcept : any_many_sender() {
: any_many_sender() {
struct s { struct s {
static void op(data& src, data* dst) { static void op(data& src, data* dst) {
if (dst) if (dst)
new (dst->buffer_) Wrapped( new (dst->buffer_)
std::move(*static_cast<Wrapped*>((void*)src.buffer_))); Wrapped(std::move(*static_cast<Wrapped*>((void*)src.buffer_)));
static_cast<Wrapped const*>((void*)src.buffer_)->~Wrapped(); static_cast<Wrapped const*>((void*)src.buffer_)->~Wrapped();
} }
static any_executor<E> executor(data& src) { static any_executor<E> executor(data& src) {
return any_executor<E>{::pushmi::executor(*static_cast<Wrapped*>((void*)src.buffer_))}; return any_executor<E>{
::pushmi::executor(*static_cast<Wrapped*>((void*)src.buffer_))};
} }
static void submit(data& src, any_receiver<E, VN...> out) { static void submit(data& src, any_receiver<E, VN...> out) {
::pushmi::submit( ::pushmi::submit(
...@@ -74,21 +88,24 @@ class any_many_sender { ...@@ -74,21 +88,24 @@ class any_many_sender {
} }
template <class T, class U = std::decay_t<T>> template <class T, class U = std::decay_t<T>>
using wrapped_t = using wrapped_t =
std::enable_if_t<!std::is_same<U, any_many_sender>::value, U>; std::enable_if_t<!std::is_same<U, any_many_sender>::value, U>;
public: public:
using properties = property_set<is_sender<>, is_many<>>; using properties = property_set<is_sender<>, is_many<>>;
any_many_sender() = default; any_many_sender() = default;
any_many_sender(any_many_sender&& that) noexcept any_many_sender(any_many_sender&& that) noexcept : any_many_sender() {
: any_many_sender() {
that.vptr_->op_(that.data_, &data_); that.vptr_->op_(that.data_, &data_);
std::swap(that.vptr_, vptr_); std::swap(that.vptr_, vptr_);
} }
PUSHMI_TEMPLATE(class Wrapped) PUSHMI_TEMPLATE(class Wrapped)
(requires SenderTo<wrapped_t<Wrapped>, any_receiver<E, VN...>, is_many<>>) (requires SenderTo<
wrapped_t<Wrapped>,
any_receiver<E, VN...>,
is_many<>>)
explicit any_many_sender(Wrapped obj) noexcept(insitu<Wrapped>()) explicit any_many_sender(Wrapped obj) noexcept(insitu<Wrapped>())
: any_many_sender{std::move(obj), bool_<insitu<Wrapped>()>{}} {} : any_many_sender{std::move(obj), bool_<insitu<Wrapped>()>{}} {}
~any_many_sender() { ~any_many_sender() {
vptr_->op_(data_, nullptr); vptr_->op_(data_, nullptr);
} }
...@@ -108,7 +125,7 @@ class any_many_sender { ...@@ -108,7 +125,7 @@ class any_many_sender {
// Class static definitions: // Class static definitions:
template <class E, class... VN> template <class E, class... VN>
constexpr typename any_many_sender<E, VN...>::vtable const constexpr typename any_many_sender<E, VN...>::vtable const
any_many_sender<E, VN...>::noop_; any_many_sender<E, VN...>::noop_;
template <class SF, class EXF> template <class SF, class EXF>
class many_sender<SF, EXF> { class many_sender<SF, EXF> {
...@@ -119,14 +136,16 @@ class many_sender<SF, EXF> { ...@@ -119,14 +136,16 @@ class many_sender<SF, EXF> {
using properties = property_set<is_sender<>, is_many<>>; using properties = property_set<is_sender<>, is_many<>>;
constexpr many_sender() = default; constexpr many_sender() = default;
constexpr explicit many_sender(SF sf) constexpr explicit many_sender(SF sf) : sf_(std::move(sf)) {}
: sf_(std::move(sf)) {}
constexpr many_sender(SF sf, EXF exf) constexpr many_sender(SF sf, EXF exf)
: sf_(std::move(sf)), exf_(std::move(exf)) {} : sf_(std::move(sf)), exf_(std::move(exf)) {}
auto executor() { return exf_(); } auto executor() {
return exf_();
}
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP(lazy::Receiver<Out> PUSHMI_AND lazy::Invocable<SF&, Out>)) (requires PUSHMI_EXP(lazy::Receiver<Out> PUSHMI_AND
lazy::Invocable<SF&, Out>))
void submit(Out out) { void submit(Out out) {
sf_(std::move(out)); sf_(std::move(out));
} }
...@@ -139,29 +158,32 @@ class many_sender<Data, DSF, DEXF> { ...@@ -139,29 +158,32 @@ class many_sender<Data, DSF, DEXF> {
DEXF exf_; DEXF exf_;
public: public:
using properties = property_set_insert_t<properties_t<Data>, property_set<is_sender<>, is_many<>>>; using properties = property_set_insert_t<
properties_t<Data>,
property_set<is_sender<>, is_many<>>>;
constexpr many_sender() = default; constexpr many_sender() = default;
constexpr explicit many_sender(Data data) constexpr explicit many_sender(Data data) : data_(std::move(data)) {}
: data_(std::move(data)) {}
constexpr many_sender(Data data, DSF sf) constexpr many_sender(Data data, DSF sf)
: data_(std::move(data)), sf_(std::move(sf)) {} : data_(std::move(data)), sf_(std::move(sf)) {}
constexpr many_sender(Data data, DSF sf, DEXF exf) constexpr many_sender(Data data, DSF sf, DEXF exf)
: data_(std::move(data)), sf_(std::move(sf)), exf_(std::move(exf)) {} : data_(std::move(data)), sf_(std::move(sf)), exf_(std::move(exf)) {}
auto executor() { return exf_(data_); } auto executor() {
return exf_(data_);
}
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires PUSHMI_EXP(lazy::Receiver<Out> PUSHMI_AND (requires PUSHMI_EXP(
lazy::Invocable<DSF&, Data&, Out>)) lazy::Receiver<Out> PUSHMI_AND
lazy::Invocable<DSF&, Data&, Out>))
void submit(Out out) { void submit(Out out) {
sf_(data_, std::move(out)); sf_(data_, std::move(out));
} }
}; };
template <> template <>
class many_sender<> class many_sender<> : public many_sender<ignoreSF, trampolineEXF> {
: public many_sender<ignoreSF, trampolineEXF> { public:
public:
many_sender() = default; many_sender() = default;
}; };
...@@ -227,5 +249,4 @@ many_sender(Data, DSF, DEXF) -> many_sender<Data, DSF, DEXF>; ...@@ -227,5 +249,4 @@ many_sender(Data, DSF, DEXF) -> many_sender<Data, DSF, DEXF>;
template<> template<>
struct construct_deduced<many_sender> : make_many_sender_fn {}; struct construct_deduced<many_sender> : make_many_sender_fn {};
} // namespace pushmi } // namespace pushmi
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/executor.h> #include <folly/experimental/pushmi/executor.h>
#include <folly/experimental/pushmi/trampoline.h> #include <folly/experimental/pushmi/trampoline.h>
...@@ -13,11 +24,18 @@ namespace pushmi { ...@@ -13,11 +24,18 @@ namespace pushmi {
// //
struct new_thread_executor { struct new_thread_executor {
using properties = property_set<is_sender<>, is_executor<>, is_never_blocking<>, is_concurrent_sequence<>, is_single<>>; using properties = property_set<
is_sender<>,
is_executor<>,
is_never_blocking<>,
is_concurrent_sequence<>,
is_single<>>;
new_thread_executor executor() { return {}; } new_thread_executor executor() {
return {};
}
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out>) (requires Receiver<Out>)
void submit(Out out) { void submit(Out out) {
std::thread t{[out = std::move(out)]() mutable { std::thread t{[out = std::move(out)]() mutable {
auto tr = ::pushmi::trampoline(); auto tr = ::pushmi::trampoline();
......
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/o/extension_operators.h>
#include <folly/experimental/pushmi/o/submit.h>
#include <folly/experimental/pushmi/receiver.h> #include <folly/experimental/pushmi/receiver.h>
#include <folly/experimental/pushmi/single_sender.h> #include <folly/experimental/pushmi/single_sender.h>
#include <folly/experimental/pushmi/o/submit.h>
#include <folly/experimental/pushmi/o/extension_operators.h>
namespace pushmi { namespace pushmi {
namespace operators { namespace operators {
PUSHMI_INLINE_VAR constexpr struct defer_fn { PUSHMI_INLINE_VAR constexpr struct defer_fn {
private: private:
template <class F> template <class F>
struct impl { struct impl {
F f_; F f_;
PUSHMI_TEMPLATE(class Data, class Out) PUSHMI_TEMPLATE(class Data, class Out)
(requires Receiver<Out>) (requires Receiver<Out>)
void operator()(Data&, Out out) { void operator()(Data&, Out out) {
auto sender = f_(); auto sender = f_();
::pushmi::submit(sender, std::move(out)); ::pushmi::submit(sender, std::move(out));
} }
}; };
public:
public:
PUSHMI_TEMPLATE(class F) PUSHMI_TEMPLATE(class F)
(requires Invocable<F&>) (requires Invocable<F&>)
auto operator()(F f) const { auto operator()(F f) const {
struct sender_base : single_sender<> { struct sender_base : single_sender<> {
using properties = properties_t<invoke_result_t<F&>>; using properties = properties_t<invoke_result_t<F&>>;
}; };
return make_single_sender(sender_base{}, impl<F>{std::move(f)}); return make_single_sender(sender_base{}, impl<F>{std::move(f)});
} }
} defer {}; } defer{};
} // namespace operators } // namespace operators
......
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/detail/functional.h> #include <folly/experimental/pushmi/detail/functional.h>
#include <folly/experimental/pushmi/o/submit.h>
#include <folly/experimental/pushmi/o/extension_operators.h> #include <folly/experimental/pushmi/o/extension_operators.h>
#include <folly/experimental/pushmi/o/submit.h>
namespace pushmi { namespace pushmi {
namespace detail { namespace detail {
struct single_empty_sender_base : single_sender<ignoreSF, inlineEXF> { struct single_empty_sender_base : single_sender<ignoreSF, inlineEXF> {
using properties = property_set<is_sender<>, is_single<>, is_always_blocking<>, is_fifo_sequence<>>; using properties = property_set<
}; is_sender<>,
template <class... VN> is_single<>,
struct single_empty_impl { is_always_blocking<>,
PUSHMI_TEMPLATE(class Out) is_fifo_sequence<>>;
(requires ReceiveValue<Out, VN...>) };
void operator()(single_empty_sender_base&, Out out) { template <class... VN>
::pushmi::set_done(out); struct single_empty_impl {
} PUSHMI_TEMPLATE(class Out)
}; (requires ReceiveValue<Out, VN...>)
} void operator()(
single_empty_sender_base&,
Out out) {
::pushmi::set_done(out);
}
};
} // namespace detail
namespace operators { namespace operators {
template <class... VN> template <class... VN>
auto empty() { auto empty() {
return make_single_sender(detail::single_empty_sender_base{}, detail::single_empty_impl<VN...>{}); return make_single_sender(
detail::single_empty_sender_base{}, detail::single_empty_impl<VN...>{});
} }
inline auto empty() { inline auto empty() {
return make_single_sender(detail::single_empty_sender_base{}, detail::single_empty_impl<>{}); return make_single_sender(
detail::single_empty_sender_base{}, detail::single_empty_impl<>{});
} }
} // namespace operators } // namespace operators
......
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/o/submit.h>
#include <folly/experimental/pushmi/o/extension_operators.h> #include <folly/experimental/pushmi/o/extension_operators.h>
#include <folly/experimental/pushmi/o/submit.h>
namespace pushmi { namespace pushmi {
namespace detail { namespace detail {
struct single_error_sender_base : single_sender<ignoreSF, inlineEXF> { struct single_error_sender_base : single_sender<ignoreSF, inlineEXF> {
using properties = property_set<is_sender<>, is_single<>, is_always_blocking<>, is_fifo_sequence<>>; using properties = property_set<
}; is_sender<>,
template <class E, class... VN> is_single<>,
struct single_error_impl { is_always_blocking<>,
E e_; is_fifo_sequence<>>;
PUSHMI_TEMPLATE(class Out) };
(requires ReceiveError<Out, E> && ReceiveValue<Out, VN...>) template <class E, class... VN>
void operator()(single_error_sender_base&, Out out) { struct single_error_impl {
::pushmi::set_error(out, std::move(e_)); E e_;
} PUSHMI_TEMPLATE(class Out)
}; (requires ReceiveError<Out, E>&& ReceiveValue<Out, VN...>)
} void operator()(
single_error_sender_base&,
Out out) {
::pushmi::set_error(out, std::move(e_));
}
};
} // namespace detail
namespace operators { namespace operators {
PUSHMI_TEMPLATE(class... VN, class E) PUSHMI_TEMPLATE(class... VN, class E)
(requires And<SemiMovable<VN>...> && SemiMovable<E>) (requires And<SemiMovable<VN>...>&& SemiMovable<E>)
auto error(E e) { auto error(E e) {
return make_single_sender(detail::single_error_sender_base{}, detail::single_error_impl<E, VN...>{std::move(e)}); return make_single_sender(
detail::single_error_sender_base{},
detail::single_error_impl<E, VN...>{std::move(e)});
} }
} // namespace operators } // namespace operators
......
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/piping.h>
#include <folly/experimental/pushmi/o/extension_operators.h> #include <folly/experimental/pushmi/o/extension_operators.h>
#include <folly/experimental/pushmi/piping.h>
namespace pushmi { namespace pushmi {
namespace detail { namespace detail {
struct filter_fn { struct filter_fn {
private: private:
template <class In, class Predicate> template <class In, class Predicate>
struct on_value_impl { struct on_value_impl {
Predicate p_; Predicate p_;
PUSHMI_TEMPLATE(class Out, class... VN) PUSHMI_TEMPLATE(class Out, class... VN)
(requires Receiver<Out>) (requires Receiver<Out>)
void operator()(Out& out, VN&&... vn) const { void operator()(Out& out, VN&&... vn) const {
if (p_(as_const(vn)...)) { if (p_(as_const(vn)...)) {
::pushmi::set_value(out, (VN&&) vn...); ::pushmi::set_value(out, (VN &&) vn...);
} }
} }
}; };
...@@ -28,30 +39,30 @@ private: ...@@ -28,30 +39,30 @@ private:
struct submit_impl { struct submit_impl {
Predicate p_; Predicate p_;
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires Receiver<Out>) (requires Receiver<Out>)
auto operator()(Out out) const { auto operator()(Out out) const {
return ::pushmi::detail::receiver_from_fn<In>()( return ::pushmi::detail::receiver_from_fn<In>()(
std::move(out), std::move(out),
// copy 'p' to allow multiple calls to submit // copy 'p' to allow multiple calls to submit
on_value_impl<In, Predicate>{p_} on_value_impl<In, Predicate>{p_});
);
} }
}; };
template <class Predicate> template <class Predicate>
struct adapt_impl { struct adapt_impl {
Predicate p_; Predicate p_;
PUSHMI_TEMPLATE(class In) PUSHMI_TEMPLATE(class In)
(requires Sender<In>) (requires Sender<In>)
auto operator()(In in) const { auto operator()(In in) const {
return ::pushmi::detail::sender_from( return ::pushmi::detail::sender_from(
std::move(in), std::move(in),
::pushmi::detail::submit_transform_out<In>(submit_impl<In, Predicate>{p_}) ::pushmi::detail::submit_transform_out<In>(
); submit_impl<In, Predicate>{p_}));
} }
}; };
public:
public:
PUSHMI_TEMPLATE(class Predicate) PUSHMI_TEMPLATE(class Predicate)
(requires SemiMovable<Predicate>) (requires SemiMovable<Predicate>)
auto operator()(Predicate p) const { auto operator()(Predicate p) const {
return adapt_impl<Predicate>{std::move(p)}; return adapt_impl<Predicate>{std::move(p)};
} }
......
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/o/extension_operators.h> #include <folly/experimental/pushmi/o/extension_operators.h>
#include <folly/experimental/pushmi/o/submit.h> #include <folly/experimental/pushmi/o/submit.h>
...@@ -11,62 +22,79 @@ namespace pushmi { ...@@ -11,62 +22,79 @@ namespace pushmi {
namespace detail { namespace detail {
struct for_each_fn { struct for_each_fn {
private: private:
template<class... PN> template <class... PN>
struct subset { using properties = property_set<PN...>; }; struct subset {
template<class In, class Out> using properties = property_set<PN...>;
};
template <class In, class Out>
struct Pull : Out { struct Pull : Out {
explicit Pull(Out out) : Out(std::move(out)) {} explicit Pull(Out out) : Out(std::move(out)) {}
using properties = property_set_insert_t<properties_t<Out>, property_set<is_flow<>>>; using properties =
property_set_insert_t<properties_t<Out>, property_set<is_flow<>>>;
std::function<void(std::ptrdiff_t)> pull; std::function<void(std::ptrdiff_t)> pull;
template<class V> template <class V>
void value(V&& v) { void value(V&& v) {
::pushmi::set_value(static_cast<Out&>(*this), (V&&) v); ::pushmi::set_value(static_cast<Out&>(*this), (V &&) v);
pull(1); pull(1);
} }
PUSHMI_TEMPLATE(class Up) PUSHMI_TEMPLATE(class Up)
(requires Receiver<Up>) (requires Receiver<Up>)
void starting(Up up){ void starting(Up up) {
pull = [up = std::move(up)](std::ptrdiff_t requested) mutable { pull = [up = std::move(up)](std::ptrdiff_t requested) mutable {
::pushmi::set_value(up, requested); ::pushmi::set_value(up, requested);
}; };
pull(1); pull(1);
} }
PUSHMI_TEMPLATE(class Up) PUSHMI_TEMPLATE(class Up)
(requires ReceiveValue<Up>) (requires ReceiveValue<Up>)
void starting(Up){} void starting(Up) {}
}; };
template <class... AN> template <class... AN>
struct fn { struct fn {
std::tuple<AN...> args_; std::tuple<AN...> args_;
PUSHMI_TEMPLATE(class In) PUSHMI_TEMPLATE(class In)
(requires Sender<In> && Flow<In> && Many<In>) (requires Sender<In>&& Flow<In>&& Many<In>)
In operator()(In in) { In operator()(In in) {
auto out{::pushmi::detail::receiver_from_fn<subset<is_sender<>, property_set_index_t<properties_t<In>, is_single<>>>>()(std::move(args_))}; auto out{::pushmi::detail::receiver_from_fn<subset<
is_sender<>,
property_set_index_t<properties_t<In>, is_single<>>>>()(
std::move(args_))};
using Out = decltype(out); using Out = decltype(out);
::pushmi::submit(in, ::pushmi::detail::receiver_from_fn<In>()(Pull<In, Out>{std::move(out)})); ::pushmi::submit(
in,
::pushmi::detail::receiver_from_fn<In>()(
Pull<In, Out>{std::move(out)}));
return in; return in;
} }
PUSHMI_TEMPLATE(class In) PUSHMI_TEMPLATE(class In)
(requires Sender<In> && Constrained<In> && Flow<In> && Many<In>) (requires Sender<In>&& Constrained<In>&& Flow<In>&& Many<In>)
In operator()(In in) { In operator()(In in) {
auto out{::pushmi::detail::receiver_from_fn<subset<is_sender<>, property_set_index_t<properties_t<In>, is_single<>>>>()(std::move(args_))}; auto out{::pushmi::detail::receiver_from_fn<subset<
is_sender<>,
property_set_index_t<properties_t<In>, is_single<>>>>()(
std::move(args_))};
using Out = decltype(out); using Out = decltype(out);
::pushmi::submit(in, ::pushmi::top(in), ::pushmi::detail::receiver_from_fn<In>()(Pull<In, Out>{std::move(out)})); ::pushmi::submit(
in,
::pushmi::top(in),
::pushmi::detail::receiver_from_fn<In>()(
Pull<In, Out>{std::move(out)}));
return in; return in;
} }
}; };
public:
public:
template <class... AN> template <class... AN>
auto operator()(AN&&... an) const { auto operator()(AN&&... an) const {
return for_each_fn::fn<AN...>{{(AN&&) an...}}; return for_each_fn::fn<AN...>{{(AN &&) an...}};
} }
}; };
} //namespace detail } // namespace detail
namespace operators { namespace operators {
PUSHMI_INLINE_VAR constexpr detail::for_each_fn for_each{}; PUSHMI_INLINE_VAR constexpr detail::for_each_fn for_each{};
} //namespace operartors } // namespace operators
} //namespace pushmi } // namespace pushmi
This diff is collapsed.
// clang-format off
// clang format does not support the '<>' in the lambda syntax yet.. []<>()->{}
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/single_sender.h>
#include <folly/experimental/pushmi/o/submit.h>
#include <folly/experimental/pushmi/o/extension_operators.h> #include <folly/experimental/pushmi/o/extension_operators.h>
#include <folly/experimental/pushmi/o/submit.h>
#include <folly/experimental/pushmi/single_sender.h>
namespace pushmi { namespace pushmi {
namespace operators { namespace operators {
PUSHMI_INLINE_VAR constexpr struct just_fn { PUSHMI_INLINE_VAR constexpr struct just_fn {
private: private:
struct sender_base : single_sender<ignoreSF, inlineEXF> { struct sender_base : single_sender<ignoreSF, inlineEXF> {
using properties = property_set<is_sender<>, is_single<>, is_always_blocking<>, is_fifo_sequence<>>; using properties = property_set<
is_sender<>,
is_single<>,
is_always_blocking<>,
is_fifo_sequence<>>;
}; };
template <class... VN> template <class... VN>
struct impl { struct impl {
std::tuple<VN...> vn_; std::tuple<VN...> vn_;
PUSHMI_TEMPLATE (class Out) PUSHMI_TEMPLATE(class Out)
(requires ReceiveValue<Out, VN...>) (requires ReceiveValue<Out, VN...>)
void operator()(sender_base&, Out out) { void operator()(sender_base&, Out out) {
::pushmi::apply(::pushmi::set_value, std::tuple_cat(std::tuple<Out&>{out}, std::move(vn_))); ::pushmi::apply(
::pushmi::set_value,
std::tuple_cat(std::tuple<Out&>{out}, std::move(vn_)));
::pushmi::set_done(std::move(out)); ::pushmi::set_done(std::move(out));
} }
}; };
public:
public:
PUSHMI_TEMPLATE(class... VN) PUSHMI_TEMPLATE(class... VN)
(requires And<SemiMovable<VN>...>) (requires And<SemiMovable<VN>...>)
auto operator()(VN... vn) const { auto operator()(VN... vn) const {
return make_single_sender(sender_base{}, impl<VN...>{std::tuple<VN...>{std::move(vn)...}}); return make_single_sender(
sender_base{}, impl<VN...>{std::tuple<VN...>{std::move(vn)...}});
} }
} just {}; } just{};
} // namespace operators } // namespace operators
} // namespace pushmi } // namespace pushmi
#pragma once #pragma once
// Copyright (c) 2018-present, Facebook, Inc. /*
// * Copyright 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. * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/piping.h>
#include <folly/experimental/pushmi/executor.h> #include <folly/experimental/pushmi/executor.h>
#include <folly/experimental/pushmi/o/extension_operators.h> #include <folly/experimental/pushmi/o/extension_operators.h>
#include <folly/experimental/pushmi/piping.h>
namespace pushmi { namespace pushmi {
namespace detail { namespace detail {
struct on_fn { struct on_fn {
private: private:
template <class In, class Out> template <class In, class Out>
struct on_value_impl { struct on_value_impl {
In in_; In in_;
...@@ -26,12 +37,12 @@ private: ...@@ -26,12 +37,12 @@ private:
struct out_impl { struct out_impl {
ExecutorFactory ef_; ExecutorFactory ef_;
PUSHMI_TEMPLATE(class Out) PUSHMI_TEMPLATE(class Out)
(requires SenderTo<In, Out>) (requires SenderTo<In, Out>)
void operator()(In& in, Out out) const { void operator()(In& in, Out out) const {
auto exec = ef_(); auto exec = ef_();
::pushmi::submit(exec, ::pushmi::submit(
::pushmi::make_receiver(on_value_impl<In, Out>{in, std::move(out)}) exec,
); ::pushmi::make_receiver(on_value_impl<In, Out>{in, std::move(out)}));
} }
}; };
template <class In, class TP, class Out> template <class In, class TP, class Out>
...@@ -47,34 +58,34 @@ private: ...@@ -47,34 +58,34 @@ private:
struct time_out_impl { struct time_out_impl {
ExecutorFactory ef_; ExecutorFactory ef_;
PUSHMI_TEMPLATE(class TP, class Out) PUSHMI_TEMPLATE(class TP, class Out)
(requires TimeSenderTo<In, Out>) (requires TimeSenderTo<In, Out>)
void operator()(In& in, TP at, Out out) const { void operator()(In& in, TP at, Out out) const {
auto exec = ef_(); auto exec = ef_();
::pushmi::submit(exec, at, ::pushmi::submit(
::pushmi::make_receiver( exec,
time_on_value_impl<In, TP, Out>{in, at, std::move(out)} at,
) ::pushmi::make_receiver(
); time_on_value_impl<In, TP, Out>{in, at, std::move(out)}));
} }
}; };
template <class ExecutorFactory> template <class ExecutorFactory>
struct in_impl { struct in_impl {
ExecutorFactory ef_; ExecutorFactory ef_;
PUSHMI_TEMPLATE (class In) PUSHMI_TEMPLATE(class In)
(requires Sender<In>) (requires Sender<In>)
auto operator()(In in) const { auto operator()(In in) const {
return ::pushmi::detail::sender_from( return ::pushmi::detail::sender_from(
std::move(in), std::move(in),
detail::submit_transform_out<In>( detail::submit_transform_out<In>(
out_impl<In, ExecutorFactory>{ef_}, out_impl<In, ExecutorFactory>{ef_},
time_out_impl<In, ExecutorFactory>{ef_} time_out_impl<In, ExecutorFactory>{ef_}));
)
);
} }
}; };
public:
public:
PUSHMI_TEMPLATE(class ExecutorFactory) PUSHMI_TEMPLATE(class ExecutorFactory)
(requires Invocable<ExecutorFactory&> && Executor<invoke_result_t<ExecutorFactory&>>) (requires Invocable<ExecutorFactory&>&&
Executor<invoke_result_t<ExecutorFactory&>>)
auto operator()(ExecutorFactory ef) const { auto operator()(ExecutorFactory ef) const {
return in_impl<ExecutorFactory>{std::move(ef)}; return in_impl<ExecutorFactory>{std::move(ef)};
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/pushmi/o/submit.h> #include <folly/experimental/pushmi/o/submit.h>
using namespace pushmi::aliases; using namespace pushmi::aliases;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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