Commit 16351b4a authored by Dominik Charousset's avatar Dominik Charousset Committed by Dominik Charousset

Switch to a new internal source/stage/sink design

parent ee3bd69c
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_STREAM_SINK_DRIVER_IMPL_HPP
#define CAF_STREAM_SINK_DRIVER_IMPL_HPP
#include "caf/none.hpp"
#include "caf/stream_sink_driver.hpp"
#include "caf/stream_sink_trait.hpp"
namespace caf {
namespace detail {
/// Identifies an unbound sequence of messages.
template <class Input, class Process, class Finalize>
class stream_sink_driver_impl final : public stream_sink_driver<Input> {
public:
// -- member types -----------------------------------------------------------
using super = stream_sink_driver<Input>;
using input_type = typename super::input_type;
using trait = stream_sink_trait_t<Process, Finalize>;
using output_type = typename trait::output;
using state_type = typename trait::state;
template <class Init>
stream_sink_driver_impl(Init init, Process f, Finalize fin)
: process_(std::move(f)),
finalize_(std::move(fin)) {
init(state_);
}
void process(std::vector<input_type>&& xs) override {
return trait::process::invoke(process_, state_, std::move(xs));
}
message finalize() override {
return trait::finalize::invoke(finalize_, state_);
}
private:
Process process_;
Finalize finalize_;
state_type state_;
};
} // namespace detail
} // namespace caf
#endif // CAF_STREAM_SINK_DRIVER_IMPL_HPP
...@@ -33,31 +33,23 @@ ...@@ -33,31 +33,23 @@
namespace caf { namespace caf {
namespace detail { namespace detail {
template <class Fun, class Finalize> template <class Driver>
class stream_sink_impl : public stream_manager { class stream_sink_impl : public stream_manager {
public: public:
using super = stream_manager; using super = stream_manager;
using trait = stream_sink_trait_t<Fun, Finalize>; using driver_type = Driver;
using state_type = typename trait::state; using input_type = typename driver_type::input_type;
using input_type = typename trait::input; template <class... Ts>
stream_sink_impl(local_actor* self, Ts&&... xs)
using output_type = typename trait::output;
stream_sink_impl(local_actor* self, Fun fun, Finalize fin)
: stream_manager(self), : stream_manager(self),
fun_(std::move(fun)), driver_(std::forward<Ts>(xs)...),
fin_(std::move(fin)),
out_(self) { out_(self) {
// nop // nop
} }
state_type& state() {
return state_;
}
terminal_stream_scatterer& out() override { terminal_stream_scatterer& out() override {
return out_; return out_;
} }
...@@ -70,9 +62,8 @@ public: ...@@ -70,9 +62,8 @@ public:
CAF_LOG_TRACE(CAF_ARG(x)); CAF_LOG_TRACE(CAF_ARG(x));
using vec_type = std::vector<input_type>; using vec_type = std::vector<input_type>;
if (x.xs.match_elements<vec_type>()) { if (x.xs.match_elements<vec_type>()) {
auto& xs = x.xs.get_as<vec_type>(0); auto& xs = x.xs.get_mutable_as<vec_type>(0);
for (auto& x : xs) driver_.process(std::move(xs));
fun_(state_, std::move(x));
return none; return none;
} }
CAF_LOG_ERROR("received unexpected batch type"); CAF_LOG_ERROR("received unexpected batch type");
...@@ -81,23 +72,18 @@ public: ...@@ -81,23 +72,18 @@ public:
protected: protected:
message make_final_result() override { message make_final_result() override {
return trait::make_result(state_, fin_); return driver_.finalize();
} }
private: private:
state_type state_; driver_type driver_;
Fun fun_;
Finalize fin_;
terminal_stream_scatterer out_; terminal_stream_scatterer out_;
}; };
template <class Init, class Fun, class Finalize> template <class Driver, class... Ts>
stream_manager_ptr make_stream_sink(local_actor* self, Init init, Fun f, stream_manager_ptr make_stream_sink(local_actor* self, Ts&&... xs) {
Finalize fin) { using impl = stream_sink_impl<Driver>;
using impl = stream_sink_impl<Fun, Finalize>; return make_counted<impl>(self, std::forward<Ts>(xs)...);
auto ptr = make_counted<impl>(self, std::move(f), std::move(fin));
init(ptr->state());
return ptr;
} }
} // namespace detail } // namespace detail
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_STREAM_SOURCE_DRIVER_IMPL_HPP
#define CAF_STREAM_SOURCE_DRIVER_IMPL_HPP
#include "caf/none.hpp"
#include "caf/stream_source_driver.hpp"
#include "caf/stream_source_trait.hpp"
namespace caf {
namespace detail {
template <class Output, class Pull, class Done, class HandshakeData>
class stream_source_driver_impl;
/// Identifies an unbound sequence of messages.
template <class Output, class Pull, class Done, class... Ts>
class stream_source_driver_impl<Output, Pull, Done, std::tuple<Ts...>> final
: public stream_source_driver<Output, Ts...> {
public:
// -- member types -----------------------------------------------------------
using super = stream_source_driver<Output, Ts...>;
using output_type = typename super::output_type;
using stream_type = stream<output_type>;
using annotated_stream_type = typename super::annotated_stream_type;
using tuple_type = std::tuple<Ts...>;
using handshake_tuple_type = typename super::handshake_tuple_type;
using trait = stream_source_trait_t<Pull>;
using state_type = typename trait::state;
template <class Init, class Tuple>
stream_source_driver_impl(Init init, Pull f, Done pred, Tuple&& hs)
: pull_(std::move(f)),
done_(std::move(pred)),
hs_(std::forward<Tuple>(hs)) {
init(state_);
}
handshake_tuple_type make_handshake() override {
return std::tuple_cat(std::make_tuple(none), hs_);
}
void pull(downstream<output_type>& out, size_t num) override {
return pull_(state_, out, num);
}
bool done() const noexcept override {
return done_(state_);
}
private:
state_type state_;
Pull pull_;
Done done_;
tuple_type hs_;
};
} // namespace detail
} // namespace caf
#endif // CAF_STREAM_SOURCE_DRIVER_IMPL_HPP
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#define CAF_DETAIL_STREAM_SOURCE_IMPL_HPP #define CAF_DETAIL_STREAM_SOURCE_IMPL_HPP
#include "caf/downstream.hpp" #include "caf/downstream.hpp"
#include "caf/fwd.hpp"
#include "caf/logger.hpp" #include "caf/logger.hpp"
#include "caf/make_counted.hpp" #include "caf/make_counted.hpp"
#include "caf/outbound_path.hpp" #include "caf/outbound_path.hpp"
...@@ -31,70 +32,69 @@ ...@@ -31,70 +32,69 @@
namespace caf { namespace caf {
namespace detail { namespace detail {
template <class Fun, class Predicate, class DownstreamPolicy> template <class Driver, class Scatterer>
class stream_source_impl : public stream_manager { class stream_source_impl : public stream_manager {
public: public:
using trait = stream_source_trait_t<Fun>; // -- static asserts ---------------------------------------------------------
using state_type = typename trait::state; static_assert(std::is_same<typename Driver::output_type,
typename Scatterer::value_type>::value,
"Driver and Scatterer have incompatible types.");
using output_type = typename trait::output; // -- member types -----------------------------------------------------------
stream_source_impl(local_actor* self, Fun fun, Predicate pred) using driver_type = Driver;
using scatterer_type = Scatterer;
using output_type = typename driver_type::output_type;
// -- constructors, destructors, and assignment operators --------------------
template <class... Ts>
stream_source_impl(local_actor* self, Ts&&... xs)
: stream_manager(self), : stream_manager(self),
at_end_(false), at_end_(false),
fun_(std::move(fun)), driver_(std::forward<Ts>(xs)...),
pred_(std::move(pred)),
out_(self) { out_(self) {
// nop // nop
} }
// -- implementation of virtual functions ------------------------------------
bool done() const override { bool done() const override {
return at_end_ && out_.clean(); return at_end_ && out_.clean();
} }
Scatterer& out() override {
DownstreamPolicy& out() override {
return out_; return out_;
} }
bool generate_messages() override { bool generate_messages() override {
if (at_end_) if (at_end_)
return false; return false;
auto hint = out_.capacity(); auto hint = out_.capacity();
if (hint == 0) if (hint == 0)
return false; return false;
downstream<typename DownstreamPolicy::value_type> ds{out_.buf()}; downstream<output_type> ds{out_.buf()};
fun_(state_, ds, hint); driver_.pull(ds, hint);
if (pred_(state_)) if (driver_.done())
at_end_ = true; at_end_ = true;
return hint != out_.capacity(); return hint != out_.capacity();
} }
state_type& state() {
return state_;
}
bool at_end() const noexcept {
return at_end_;;
}
private: private:
bool at_end_; bool at_end_;
state_type state_; Driver driver_;
Fun fun_; Scatterer out_;
Predicate pred_;
DownstreamPolicy out_;
}; };
template <class Init, class Fun, class Predicate, class Scatterer> template <class Driver,
stream_manager_ptr make_stream_source(local_actor* self, Init init, Fun f, class Scatterer = broadcast_scatterer<typename Driver::output_type>,
Predicate p, policy::arg<Scatterer>) { class... Ts>
using impl = stream_source_impl < Fun, Predicate, Scatterer>; stream_manager_ptr make_stream_source(local_actor* self, Ts&&... xs) {
auto ptr = make_counted<impl>(self, std::move(f), std::move(p)); using impl = stream_source_impl<Driver, Scatterer>;
init(ptr->state()); return make_counted<impl>(self, std::forward<Ts>(xs)...);
return ptr;
} }
} // namespace detail } // namespace detail
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_STREAM_STAGE_DRIVER_IMPL_HPP
#define CAF_STREAM_STAGE_DRIVER_IMPL_HPP
#include "caf/none.hpp"
#include "caf/stream_stage_driver.hpp"
#include "caf/stream_stage_trait.hpp"
namespace caf {
namespace detail {
template <class Input, class Output, class Process, class Finalize,
class HandshakeData>
class stream_stage_driver_impl;
/// Identifies an unbound sequence of messages.
template <class Input, class Output, class Process, class Finalize, class... Ts>
class stream_stage_driver_impl<Input, Output, Process, Finalize,
std::tuple<Ts...>> final
: public stream_stage_driver<Output, Ts...> {
public:
// -- member types -----------------------------------------------------------
using super = stream_stage_driver<Input, Output, Ts...>;
using input_type = typename super::output_type;
using output_type = typename super::output_type;
using stream_type = stream<output_type>;
using annotated_stream_type = typename super::annotated_stream_type;
using tuple_type = std::tuple<Ts...>;
using handshake_tuple_type = typename super::handshake_tuple_type;
using trait = stream_stage_trait_t<Process>;
using state_type = typename trait::state;
template <class Init, class Tuple>
stream_stage_driver_impl(Init init, Process f, Finalize fin, Tuple&& hs)
: process_(std::move(f)),
fin_(std::move(fin)),
hs_(std::forward<Tuple>(hs)) {
init(state_);
}
handshake_tuple_type make_handshake() override {
return std::tuple_cat(std::make_tuple(none), hs_);
}
void process(std::vector<input_type>&& batch,
downstream<output_type>& out) override {
trait::process::invoke(process_, state_, std::move(batch), out);
}
void finalize() override {
return fin_();
}
private:
state_type state_;
Process process_;
Finalize fin_;
tuple_type hs_;
};
} // namespace detail
} // namespace caf
#endif // CAF_STREAM_STAGE_DRIVER_IMPL_HPP
...@@ -32,30 +32,36 @@ ...@@ -32,30 +32,36 @@
namespace caf { namespace caf {
namespace detail { namespace detail {
template <class Fun, class Cleanup, class DownstreamPolicy> template <class Driver, class Scatterer>
class stream_stage_impl : public stream_manager { class stream_stage_impl : public stream_manager {
public: public:
using trait = stream_stage_trait_t<Fun>; // -- static asserts ---------------------------------------------------------
using state_type = typename trait::state; static_assert(std::is_same<typename Driver::output_type,
typename Scatterer::value_type>::value,
"Driver and Scatterer have incompatible types.");
using input_type = typename trait::input; // -- member types -----------------------------------------------------------
using output_type = typename trait::output; using driver_type = Driver;
stream_stage_impl(local_actor* self, Fun fun, Cleanup cleanup) using scatterer_type = Scatterer;
using output_type = typename driver_type::output_type;
// -- constructors, destructors, and assignment operators --------------------
template <class... Ts>
stream_stage_impl(local_actor* self, Ts&&... xs)
: stream_manager(self), : stream_manager(self),
fun_(std::move(fun)), driver_(std::forward<Ts>(xs)...),
cleanup_(std::move(cleanup)),
out_(self) { out_(self) {
// nop // nop
} }
state_type& state() { // -- implementation of virtual functions ------------------------------------
return state_;
}
DownstreamPolicy& out() override { scatterer_type& out() override {
return out_; return out_;
} }
...@@ -67,10 +73,9 @@ public: ...@@ -67,10 +73,9 @@ public:
CAF_LOG_TRACE(CAF_ARG(x)); CAF_LOG_TRACE(CAF_ARG(x));
using vec_type = std::vector<output_type>; using vec_type = std::vector<output_type>;
if (x.xs.match_elements<vec_type>()) { if (x.xs.match_elements<vec_type>()) {
auto& xs = x.xs.get_as<vec_type>(0); auto& xs = x.xs.get_mutable_as<vec_type>(0);
downstream<typename DownstreamPolicy::value_type> ds{out_.buf()}; downstream<output_type> ds{out_.buf()};
for (auto& x : xs) driver_.process(std::move(xs), ds);
fun_(state_, ds, std::move(x));
return none; return none;
} }
CAF_LOG_ERROR("received unexpected batch type"); CAF_LOG_ERROR("received unexpected batch type");
...@@ -78,8 +83,7 @@ public: ...@@ -78,8 +83,7 @@ public:
} }
message make_output_token(const stream_id&) const override { message make_output_token(const stream_id&) const override {
// TODO: return make_message(stream<output_type>{x}); return make_message_from_tuple(driver_.make_handshake());
return make_message();
} }
bool congested() const override { bool congested() const override {
...@@ -87,19 +91,16 @@ public: ...@@ -87,19 +91,16 @@ public:
} }
private: private:
state_type state_; driver_type driver_;
Fun fun_; scatterer_type out_;
Cleanup cleanup_;
DownstreamPolicy out_;
}; };
template <class Init, class Fun, class Cleanup, class Scatterer> template <class Driver,
stream_manager_ptr make_stream_stage(local_actor* self, Init init, Fun f, class Scatterer = broadcast_scatterer<typename Driver::output_type>,
Cleanup cleanup, policy::arg<Scatterer>) { class... Ts>
using impl = stream_stage_impl<Fun, Cleanup, Scatterer>; stream_manager_ptr make_stream_stage(local_actor* self, Ts&&... xs) {
auto ptr = make_counted<impl>(self, std::move(f), std::move(cleanup)); using impl = stream_stage_impl<Driver, Scatterer>;
init(ptr->state()); return make_counted<impl>(self, std::forward<Ts>(xs)...);
return ptr;
} }
} // namespace detail } // namespace detail
......
...@@ -48,6 +48,11 @@ public: ...@@ -48,6 +48,11 @@ public:
buf_.emplace_back(std::forward<Ts>(xs)...); buf_.emplace_back(std::forward<Ts>(xs)...);
} }
template <class Iterator, class Sentinel>
void append(Iterator first, Sentinel last) {
buf_.insert(buf_.end(), first, last);
}
// @private // @private
queue_type& buf() { queue_type& buf() {
return buf_; return buf_;
......
...@@ -35,6 +35,7 @@ template <class> class intrusive_ptr; ...@@ -35,6 +35,7 @@ template <class> class intrusive_ptr;
template <class> class behavior_type_of; template <class> class behavior_type_of;
template <class> class trivial_match_case; template <class> class trivial_match_case;
template <class> class weak_intrusive_ptr; template <class> class weak_intrusive_ptr;
template <class> class broadcast_scatterer;
template <class> struct timeout_definition; template <class> struct timeout_definition;
......
...@@ -71,16 +71,15 @@ public: ...@@ -71,16 +71,15 @@ public:
// -- downstream communication ----------------------------------------------- // -- downstream communication -----------------------------------------------
/// Sets `open_credit` to `initial_credit` and clears `cached_handshake`.
void handle_ack_open(long initial_credit);
/// Sends a stream handshake. /// Sends a stream handshake.
void emit_open(local_actor* self, strong_actor_ptr origin, static void emit_open(local_actor* self, stream_slot slot,
mailbox_element::forwarding_stack stages, message_id mid, strong_actor_ptr to, message handshake_data,
message handshake_data, stream_priority prio, stream_priority prio, bool is_redeployable);
bool is_redeployable);
/// Sends a `stream_msg::batch` on this path, decrements `open_credit` by /// Sends a `stream_msg::batch` on this path, decrements `open_credit` by
/// Sets `open_credit` to `initial_credit` and clears `cached_handshake`.
void handle_ack_open(long initial_credit);
/// `xs_size` and increments `next_batch_id` by 1. /// `xs_size` and increments `next_batch_id` by 1.
void emit_batch(local_actor* self, long xs_size, message xs); void emit_batch(local_actor* self, long xs_size, message xs);
......
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_STREAM_SINK_DRIVER_HPP
#define CAF_STREAM_SINK_DRIVER_HPP
#include <tuple>
#include <vector>
#include "caf/fwd.hpp"
#include "caf/message.hpp"
#include "caf/make_message.hpp"
namespace caf {
/// Identifies an unbound sequence of messages.
template <class Input>
class stream_sink_driver {
public:
// -- member types -----------------------------------------------------------
using input_type = Input;
// -- constructors, destructors, and assignment operators --------------------
virtual ~stream_sink_driver() {
// nop
}
// -- virtual functions ------------------------------------------------------
/// Cleans up any state and produces a result message.
virtual message finalize() {
return make_message();
}
// -- pure virtual functions -------------------------------------------------
/// Processes a single batch.
virtual void process(std::vector<input_type>&& batch) = 0;
};
} // namespace caf
#endif // CAF_STREAM_SINK_DRIVER_HPP
...@@ -26,32 +26,110 @@ ...@@ -26,32 +26,110 @@
namespace caf { namespace caf {
template <class Fun, class Fin> namespace detail {
struct stream_sink_trait;
template <class State, class In, class Out> // -- invoke helper to support element-wise and batch-wise processing ----------
struct stream_sink_trait<void (State&, In), Out (State&)> {
using state = State; struct stream_sink_trait_invoke_one {
using input = In; template <class F, class State, class In>
using output = Out; static void invoke(F& f, State& st, std::vector<In>&& xs) {
template <class F> for (auto& x : xs)
static message make_result(state& st, F f) { f(st, std::move(x));
}
};
struct stream_sink_trait_invoke_all {
template <class F, class State, class In>
static void invoke(F& f, State& st, std::vector<In>&& xs) {
f(st, std::move(xs));
}
};
// -- result helper to support void and non-void functions ---------------------
struct stream_sink_trait_default_finalize {
template <class F, class State>
static message invoke(F& f, State& st) {
return make_message(f(st)); return make_message(f(st));
} }
}; };
template <class State, class In> struct stream_sink_trait_void_finalize {
struct stream_sink_trait<void (State&, In), void (State&)> { template <class F, class State>
using state = State; static message invoke(F& f, State& st) {
using input = In;
using output = void;
template <class F>
static message make_result(state& st, F& f) {
f(st); f(st);
return make_message(); return make_message();
} }
}; };
} // namespace detail
// -- trait implementation -----------------------------------------------------
/// Base type for all sink traits.
template <class State, class In, class Out>
struct stream_sink_trait_base {
/// Defines the state element for the function objects.
using state = State;
/// Defines the type of a single stream element.
using input = In;
/// Defines the result type of the sink.
using output = Out;
};
/// Defines required type aliases for stream sinks.
template <class Fun, class Fin>
struct stream_sink_trait;
/// Specializes the trait for element-wise processing with result.
template <class State, class In, class Out>
struct stream_sink_trait<void(State&, In), Out(State&)>
: stream_sink_trait_base<State, In, Out> {
/// Defines a helper for dispatching to the finalizing function object.
using finalize = detail::stream_sink_trait_default_finalize;
/// Defines a helper for dispatching to the processing function object.
using process = detail::stream_sink_trait_invoke_one;
};
/// Specializes the trait for element-wise processing without result.
template <class State, class In>
struct stream_sink_trait<void(State&, In), void(State&)>
: stream_sink_trait_base<State, In, void> {
/// Defines a helper for dispatching to the finalizing function object.
using finalize = detail::stream_sink_trait_void_finalize;
/// Defines a helper for dispatching to the processing function object.
using process = detail::stream_sink_trait_invoke_one;
};
/// Specializes the trait for batch-wise processing with result.
template <class State, class In, class Out>
struct stream_sink_trait<void(State&, std::vector<In>&), Out(State&)>
: stream_sink_trait_base<State, In, Out> {
/// Defines a helper for dispatching to the finalizing function object.
using finalize = detail::stream_sink_trait_default_finalize;
/// Defines a helper for dispatching to the processing function object.
using process = detail::stream_sink_trait_invoke_all;
};
/// Specializes the trait for batch-wise processing without result.
template <class State, class In>
struct stream_sink_trait<void(State&, std::vector<In>&), void(State&)>
: stream_sink_trait_base<State, In, void> {
/// Defines a helper for dispatching to the finalizing function object.
using finalize = detail::stream_sink_trait_void_finalize;
/// Defines a helper for dispatching to the processing function object.
using process = detail::stream_sink_trait_invoke_all;
};
// -- convenience alias --------------------------------------------------------
/// Derives a sink trait from the signatures of Fun and Fin.
template <class Fun, class Fin> template <class Fun, class Fin>
using stream_sink_trait_t = using stream_sink_trait_t =
stream_sink_trait<typename detail::get_callable_trait<Fun>::fun_sig, stream_sink_trait<typename detail::get_callable_trait<Fun>::fun_sig,
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_STREAM_SOURCE_DRIVER_HPP
#define CAF_STREAM_SOURCE_DRIVER_HPP
#include <tuple>
#include "caf/fwd.hpp"
namespace caf {
/// Identifies an unbound sequence of messages.
template <class Output, class... HandshakeData>
class stream_source_driver {
public:
// -- member types -----------------------------------------------------------
using output_type = Output;
using stream_type = stream<output_type>;
using annotated_stream_type = annotated_stream<output_type, HandshakeData...>;
using handshake_tuple_type = std::tuple<stream_type, HandshakeData...>;
// -- constructors, destructors, and assignment operators --------------------
virtual ~stream_source_driver() {
// nop
}
// -- virtual functions ------------------------------------------------------
/// Cleans up any state.
virtual void finalize() {
// nop
}
// -- pure virtual functions -------------------------------------------------
/// Generates handshake data for the next actor in the pipeline.
virtual handshake_tuple_type make_handshake() const = 0;
/// Generates more stream elements.
virtual void pull(downstream<output_type>& out, size_t num) = 0;
/// Returns `true` if the source is done sending, otherwise `false`.
virtual bool done() const noexcept = 0;
};
} // namespace caf
#endif // CAF_STREAM_SOURCE_DRIVER_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_STREAM_STAGE_DRIVER_HPP
#define CAF_STREAM_STAGE_DRIVER_HPP
#include <tuple>
#include <vector>
#include "caf/fwd.hpp"
namespace caf {
/// Identifies an unbound sequence of messages.
template <class Input, class Output, class... HandshakeData>
class stream_stage_driver {
public:
// -- member types -----------------------------------------------------------
using input_type = Input;
using output_type = Output;
using stream_type = stream<output_type>;
using annotated_stream_type = annotated_stream<output_type, HandshakeData...>;
using handshake_tuple_type = std::tuple<stream_type, HandshakeData...>;
// -- constructors, destructors, and assignment operators --------------------
virtual ~stream_stage_driver() {
// nop
}
// -- virtual functions ------------------------------------------------------
/// Cleans up any state.
virtual void finalize() {
// nop
}
// -- pure virtual functions -------------------------------------------------
/// Generates handshake data for the next actor in the pipeline.
virtual handshake_tuple_type make_handshake() const = 0;
/// Processes a single batch.
virtual void process(std::vector<input_type>&& batch,
downstream<output_type>& out) = 0;
};
} // namespace caf
#endif // CAF_STREAM_STAGE_DRIVER_HPP
...@@ -19,11 +19,39 @@ ...@@ -19,11 +19,39 @@
#ifndef CAF_STREAM_STAGE_TRAIT_HPP #ifndef CAF_STREAM_STAGE_TRAIT_HPP
#define CAF_STREAM_STAGE_TRAIT_HPP #define CAF_STREAM_STAGE_TRAIT_HPP
#include <vector>
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
namespace caf { namespace caf {
namespace detail {
// -- invoke helper to support element-wise and batch-wise processing ----------
struct stream_stage_trait_invoke_one {
template <class F, class State, class In, class Out>
static void invoke(F& f, State& st, std::vector<In>&& xs,
downstream<Out>& out) {
for (auto& x : xs)
f(st, out, std::move(x));
}
};
struct stream_stage_trait_invoke_all {
template <class F, class State, class In, class Out>
static void invoke(F& f, State& st, std::vector<In>&& xs,
downstream<Out>& out) {
f(st, std::move(xs), out);
}
};
} // namespace detail
// -- trait implementation -----------------------------------------------------
template <class F> template <class F>
struct stream_stage_trait; struct stream_stage_trait;
...@@ -32,8 +60,19 @@ struct stream_stage_trait<void (State&, downstream<Out>&, In)> { ...@@ -32,8 +60,19 @@ struct stream_stage_trait<void (State&, downstream<Out>&, In)> {
using state = State; using state = State;
using input = In; using input = In;
using output = Out; using output = Out;
using invoke = detail::stream_stage_trait_invoke_one;
};
template <class State, class In, class Out>
struct stream_stage_trait<void (State&, std::vector<In>&&, downstream<Out>&)> {
using state = State;
using input = In;
using output = Out;
using invoke = detail::stream_stage_trait_invoke_all;
}; };
// -- convenience alias --------------------------------------------------------
template <class F> template <class F>
using stream_stage_trait_t = using stream_stage_trait_t =
stream_stage_trait<typename detail::get_callable_trait<F>::fun_sig>; stream_stage_trait<typename detail::get_callable_trait<F>::fun_sig>;
......
...@@ -18,10 +18,10 @@ ...@@ -18,10 +18,10 @@
#include "caf/outbound_path.hpp" #include "caf/outbound_path.hpp"
#include "caf/send.hpp" #include "caf/local_actor.hpp"
#include "caf/logger.hpp" #include "caf/logger.hpp"
#include "caf/no_stages.hpp" #include "caf/no_stages.hpp"
#include "caf/local_actor.hpp" #include "caf/send.hpp"
namespace caf { namespace caf {
...@@ -40,6 +40,17 @@ outbound_path::~outbound_path() { ...@@ -40,6 +40,17 @@ outbound_path::~outbound_path() {
// nop // nop
} }
void outbound_path::emit_open(local_actor* self, stream_slot slot,
strong_actor_ptr to, message handshake_data,
stream_priority prio, bool is_redeployable) {
CAF_ASSERT(self != nullptr);
CAF_ASSERT(to != nullptr);
// TODO: attach an aborter to `to`
unsafe_send_as(self, to,
open_stream_msg{slot, std::move(handshake_data), self->ctrl(),
nullptr, prio, is_redeployable});
}
void outbound_path::emit_batch(local_actor* self, long xs_size, message xs) { void outbound_path::emit_batch(local_actor* self, long xs_size, message xs) {
CAF_ASSERT(open_credit >= xs_size); CAF_ASSERT(open_credit >= xs_size);
open_credit -= xs_size; open_credit -= xs_size;
......
...@@ -671,6 +671,18 @@ void scheduled_actor::push_to_cache(mailbox_element_ptr ptr) { ...@@ -671,6 +671,18 @@ void scheduled_actor::push_to_cache(mailbox_element_ptr ptr) {
q->cache().push_back(ptr.release()); q->cache().push_back(ptr.release());
} }
stream_slot scheduled_actor::next_slot() {
stream_slot result = 0;
auto nslot = [](stream_slot x) -> stream_slot {
return x + 1;
};
if (!stream_managers_.empty())
result = std::max(nslot(stream_managers_.rbegin()->first.receiver), result);
if (!pending_stream_managers_.empty())
result = std::max(nslot(pending_stream_managers_.rbegin()->first), result);
return result;
}
/* /*
bool scheduled_actor::handle_stream_msg(mailbox_element& x, bool scheduled_actor::handle_stream_msg(mailbox_element& x,
behavior* active_behavior) { behavior* active_behavior) {
......
...@@ -46,7 +46,10 @@ ...@@ -46,7 +46,10 @@
#include "caf/send.hpp" #include "caf/send.hpp"
#include "caf/stream_manager.hpp" #include "caf/stream_manager.hpp"
#include "caf/stream_scatterer.hpp" #include "caf/stream_scatterer.hpp"
#include "caf/stream_sink_driver.hpp"
#include "caf/stream_slot.hpp" #include "caf/stream_slot.hpp"
#include "caf/stream_source_driver.hpp"
#include "caf/stream_stage_driver.hpp"
#include "caf/system_messages.hpp" #include "caf/system_messages.hpp"
#include "caf/upstream_msg.hpp" #include "caf/upstream_msg.hpp"
#include "caf/variant.hpp" #include "caf/variant.hpp"
...@@ -314,22 +317,32 @@ public: ...@@ -314,22 +317,32 @@ public:
auto slot = next_slot_++; auto slot = next_slot_++;
CAF_MESSAGE(name_ << " starts streaming to " << ref.name() CAF_MESSAGE(name_ << " starts streaming to " << ref.name()
<< " on slot " << slot); << " on slot " << slot);
strong_actor_ptr to = ref.ctrl(); outbound_path::emit_open(this, slot, ref.ctrl(), make_message(),
send(to, open_stream_msg{slot, make_message(), ctrl(), nullptr, stream_priority::normal, false);
stream_priority::normal, false}); struct driver final : public stream_source_driver<int> {
auto init = [](int& x) { public:
x = 0; driver(int sentinel) : x_(0), sentinel_(sentinel) {
}; // nop
auto f = [=](int& x, downstream<int>& out, size_t hint) { }
auto y = std::min(num_messages, x + static_cast<int>(hint));
while (x < y) handshake_tuple_type make_handshake() const override {
out.push(x++); return std::make_tuple(none);
}; }
auto fin = [=](const int& x) {
return x == num_messages; void pull(downstream<int>& out, size_t hint) override {
auto y = std::min(sentinel_, x_ + static_cast<int>(hint));
while (x_ < y)
out.push(x_++);
}
bool done() const noexcept override {
return x_ == sentinel_;
}
private:
int x_;
int sentinel_;
}; };
policy::arg<broadcast_scatterer<int>> token; auto ptr = detail::make_stream_source<driver>(this, num_messages);
auto ptr = detail::make_stream_source(this, init, f, fin, token);
ptr->generate_messages(); ptr->generate_messages();
pending_managers_.emplace(slot, std::move(ptr)); pending_managers_.emplace(slot, std::move(ptr));
} }
...@@ -341,19 +354,24 @@ public: ...@@ -341,19 +354,24 @@ public:
strong_actor_ptr to = ref.ctrl(); strong_actor_ptr to = ref.ctrl();
send(to, open_stream_msg{slot, make_message(), ctrl(), nullptr, send(to, open_stream_msg{slot, make_message(), ctrl(), nullptr,
stream_priority::normal, false}); stream_priority::normal, false});
using log_ptr = vector<int>*; struct driver final : public stream_stage_driver<int, int> {
auto init = [&](log_ptr& ptr) { public:
ptr = &data; driver(vector<int>* log) : log_(log) {
}; // nop
auto f = [](log_ptr& ptr, downstream<int>& out, int x) { }
ptr->push_back(x);
out.push(x); handshake_tuple_type make_handshake() const override {
}; return std::make_tuple(none);
auto cleanup = [](log_ptr&) { }
// nop
void process(vector<int>&& batch, downstream<int>& out) override {
log_->insert(log_->end(), batch.begin(), batch.end());
out.append(batch.begin(), batch.end());
}
private:
vector<int>* log_;
}; };
policy::arg<broadcast_scatterer<int>> token; forwarder = detail::make_stream_stage<driver>(this, &data);
forwarder = detail::make_stream_stage(this, init, f, cleanup, token);
pending_managers_.emplace(slot, forwarder); pending_managers_.emplace(slot, forwarder);
} }
...@@ -367,20 +385,20 @@ public: ...@@ -367,20 +385,20 @@ public:
// was called and we run as a stage. // was called and we run as a stage.
auto mgr = forwarder; auto mgr = forwarder;
if (mgr == nullptr) { if (mgr == nullptr) {
using log_ptr = vector<int>*; struct driver final : public stream_sink_driver<int> {
auto init = [&](log_ptr& ptr) { public:
ptr = &data; driver(std::vector<int>* log) : log_(log) {
}; // nop
auto f = [](log_ptr& ptr, int x) { }
ptr->push_back(x);
}; void process(std::vector<int>&& xs) override {
auto fin = [](log_ptr&) { log_->insert(log_->end(), xs.begin(), xs.end());
// nop }
private:
vector<int>* log_;
}; };
mgr = detail::make_stream_sink(this, std::move(init), std::move(f), mgr = detail::make_stream_sink<driver>(this, &data);
std::move(fin));
} }
// mgr->out().add_path(id, hs.prev_stage);
managers_.emplace(id, mgr); managers_.emplace(id, mgr);
// Create a new queue in the mailbox for incoming traffic. // Create a new queue in the mailbox for incoming traffic.
auto ip = new inbound_path(mgr, id, hs.prev_stage); auto ip = new inbound_path(mgr, id, hs.prev_stage);
......
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