Commit 5ead6f95 authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'topic/inspector-api-integration'

parents 4c16673b 9869d7e0
...@@ -37,7 +37,7 @@ MacroBlockEnd: "^END_STATE$|CAF_END_TYPE_ID_BLOCK" ...@@ -37,7 +37,7 @@ MacroBlockEnd: "^END_STATE$|CAF_END_TYPE_ID_BLOCK"
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
PenaltyBreakAssignment: 25 PenaltyBreakAssignment: 25
PenaltyBreakBeforeFirstCallParameter: 30 PenaltyBreakBeforeFirstCallParameter: 50
PenaltyReturnTypeOnItsOwnLine: 25 PenaltyReturnTypeOnItsOwnLine: 25
PointerAlignment: Left PointerAlignment: Left
ReflowComments: true ReflowComments: true
......
...@@ -127,6 +127,12 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -127,6 +127,12 @@ is based on [Keep a Changelog](https://keepachangelog.com).
*types*, but did not enforce it because the name was only used for logging. *types*, but did not enforce it because the name was only used for logging.
Since the new metrics use this name for filtering now, we enforce static names Since the new metrics use this name for filtering now, we enforce static names
in order to help avoid hard-to-find issues with the filtering mechanism. in order to help avoid hard-to-find issues with the filtering mechanism.
- The type inspection API received a complete overhaul. The new DSL for writing
`inspect` functions exposes the entire structure of an object to CAF. This
enables inspectors to read and write a wider range of data formats. In
particular human-readable, structured data such as configuration files, JSON,
XML, etc. The inspection API received too many changes to list them here.
Please refer to the manual section on type inspection instead.
### Removed ### Removed
...@@ -183,7 +189,7 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -183,7 +189,7 @@ is based on [Keep a Changelog](https://keepachangelog.com).
- Datagram servants of UDP socket managers were not added as children to their - Datagram servants of UDP socket managers were not added as children to their
parent broker on creation, which prevented proper system shutdown in some parent broker on creation, which prevented proper system shutdown in some
cases. Adding all servants consistently to the broker should make sure UDP cases. Adding all servants consistently to the broker should make sure UDP
brokers terminate correctly (#1133). brokers terminate correctly (#1133).
## [0.17.6] - 2020-07-24 ## [0.17.6] - 2020-07-24
......
...@@ -115,11 +115,11 @@ struct base_state { ...@@ -115,11 +115,11 @@ struct base_state {
} }
actor_ostream print() { actor_ostream print() {
return aout(self) << color << name << " (id = " << self->id() << "): "; return aout(self) << color << self->name() << " (id = " << self->id()
<< "): ";
} }
virtual bool init(std::string m_name, std::string m_color) { virtual bool init(std::string m_color) {
name = std::move(m_name);
color = std::move(m_color); color = std::move(m_color);
print() << "started" << color::reset_endl; print() << "started" << color::reset_endl;
return true; return true;
...@@ -130,13 +130,18 @@ struct base_state { ...@@ -130,13 +130,18 @@ struct base_state {
} }
local_actor* self; local_actor* self;
std::string name;
std::string color; std::string color;
}; };
struct client_job_state : base_state {
static inline const char* name = "curl.client-job";
using base_state::base_state;
};
// encapsulates an HTTP request // encapsulates an HTTP request
behavior client_job(stateful_actor<base_state>* self, const actor& parent) { behavior client_job(stateful_actor<client_job_state>* self,
if (!self->state.init("client-job", color::blue)) const actor& parent) {
if (!self->state.init(color::blue))
return {}; // returning an empty behavior terminates the actor return {}; // returning an empty behavior terminates the actor
self->send(parent, read_atom_v, "http://www.example.com/index.html", self->send(parent, read_atom_v, "http://www.example.com/index.html",
uint64_t{0}, uint64_t{4095}); uint64_t{0}, uint64_t{4095});
...@@ -166,26 +171,29 @@ struct client_state : base_state { ...@@ -166,26 +171,29 @@ struct client_state : base_state {
std::random_device rd; std::random_device rd;
std::default_random_engine re; std::default_random_engine re;
std::uniform_int_distribution<int> dist; std::uniform_int_distribution<int> dist;
static inline const char* name = "curl.client";
}; };
// spawns HTTP requests // spawns HTTP requests
behavior client(stateful_actor<client_state>* self, const actor& parent) { behavior client(stateful_actor<client_state>* self, const actor& parent) {
using std::chrono::milliseconds; using std::chrono::milliseconds;
self->link_to(parent); self->link_to(parent);
if (!self->state.init("client", color::green)) if (!self->state.init(color::green))
return {}; // returning an empty behavior terminates the actor return {}; // returning an empty behavior terminates the actor
self->send(self, next_atom_v); self->send(self, next_atom_v);
return {[=](next_atom) { return {
auto& st = self->state; [=](next_atom) {
st.print() << "spawn new client_job (nr. " << ++st.count << ")" auto& st = self->state;
<< color::reset_endl; st.print() << "spawn new client_job (nr. " << ++st.count << ")"
// client_job will use IO << color::reset_endl;
// and should thus be spawned in a separate thread // client_job will use IO
self->spawn<detached + linked>(client_job, parent); // and should thus be spawned in a separate thread
// compute random delay until next job is launched self->spawn<detached + linked>(client_job, parent);
auto delay = st.dist(st.re); // compute random delay until next job is launched
self->delayed_send(self, milliseconds(delay), next_atom_v); auto delay = st.dist(st.re);
}}; self->delayed_send(self, milliseconds(delay), next_atom_v);
},
};
} }
struct curl_state : base_state { struct curl_state : base_state {
...@@ -207,22 +215,23 @@ struct curl_state : base_state { ...@@ -207,22 +215,23 @@ struct curl_state : base_state {
return size; return size;
} }
bool init(std::string m_name, std::string m_color) override { bool init(std::string m_color) override {
curl = curl_easy_init(); curl = curl_easy_init();
if (curl == nullptr) if (curl == nullptr)
return false; return false;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_state::callback); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_state::callback);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
return base_state::init(std::move(m_name), std::move(m_color)); return base_state::init(std::move(m_color));
} }
CURL* curl = nullptr; CURL* curl = nullptr;
buffer_type buf; buffer_type buf;
static inline const char* name = "curl.worker";
}; };
// manages a CURL session // manages a CURL session
behavior curl_worker(stateful_actor<curl_state>* self, const actor& parent) { behavior curl_worker(stateful_actor<curl_state>* self, const actor& parent) {
if (!self->state.init("curl-worker", color::yellow)) if (!self->state.init(color::yellow))
return {}; // returning an empty behavior terminates the actor return {}; // returning an empty behavior terminates the actor
return {[=](read_atom, const std::string& fname, uint64_t offset, return {[=](read_atom, const std::string& fname, uint64_t offset,
uint64_t range) -> message { uint64_t range) -> message {
...@@ -278,10 +287,11 @@ struct master_state : base_state { ...@@ -278,10 +287,11 @@ struct master_state : base_state {
} }
std::vector<actor> idle; std::vector<actor> idle;
std::vector<actor> busy; std::vector<actor> busy;
static inline const char* name = "curl.master";
}; };
behavior curl_master(stateful_actor<master_state>* self) { behavior curl_master(stateful_actor<master_state>* self) {
if (!self->state.init("curl-master", color::magenta)) if (!self->state.init(color::magenta))
return {}; // returning an empty behavior terminates the actor return {}; // returning an empty behavior terminates the actor
// spawn workers // spawn workers
for (size_t i = 0; i < num_curl_workers; ++i) for (size_t i = 0; i < num_curl_workers; ++i)
......
...@@ -38,8 +38,8 @@ struct foo { ...@@ -38,8 +38,8 @@ struct foo {
}; };
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo& x) { bool inspect(Inspector& f, foo& x) {
return f(meta::type_name("foo"), x.a, x.b); return f.object(x).fields(f.field("a", x.a), f.field("b", x.b));
} }
// --(rst-foo-end)-- // --(rst-foo-end)--
...@@ -57,8 +57,8 @@ struct foo2 { ...@@ -57,8 +57,8 @@ struct foo2 {
// foo2 also needs to be serializable // foo2 also needs to be serializable
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo2& x) { bool inspect(Inspector& f, foo2& x) {
return f(meta::type_name("foo2"), x.a, x.b); return f.object(x).fields(f.field("a", x.a), f.field("b", x.b));
} }
// receives our custom message types // receives our custom message types
...@@ -77,7 +77,7 @@ void testee(event_based_actor* self, size_t remaining) { ...@@ -77,7 +77,7 @@ void testee(event_based_actor* self, size_t remaining) {
set_next_behavior(); set_next_behavior();
}, },
[=](const foo& val) { [=](const foo& val) {
aout(self) << to_string(val) << endl; aout(self) << deep_to_string(val) << endl;
set_next_behavior(); set_next_behavior();
}); });
} }
...@@ -90,24 +90,24 @@ void caf_main(actor_system& sys) { ...@@ -90,24 +90,24 @@ void caf_main(actor_system& sys) {
f1.a = 5; f1.a = 5;
f1.b.resize(1); f1.b.resize(1);
f1.b.back().push_back(42); f1.b.back().push_back(42);
// I/O buffer // byte buffer
binary_serializer::container_type buf; binary_serializer::container_type buf;
// write f1 to buffer // write f1 to buffer
binary_serializer bs{sys, buf}; binary_serializer sink{sys, buf};
auto e = bs(f1); if (!sink.apply_object(f1)) {
if (e) { std::cerr << "*** failed to serialize foo2: " << to_string(sink.get_error())
std::cerr << "*** unable to serialize foo2: " << to_string(e) << '\n'; << '\n';
return; return;
} }
// read f2 back from buffer // read f2 back from buffer
binary_deserializer bd{sys, buf}; binary_deserializer source{sys, buf};
e = bd(f2); if (!source.apply_object(f2)) {
if (e) { std::cerr << "*** failed to deserialize foo2: "
std::cerr << "*** unable to serialize foo2: " << to_string(e) << '\n'; << to_string(source.get_error()) << '\n';
return; return;
} }
// must be equal // must be equal
assert(to_string(f1) == to_string(f2)); assert(deep_to_string(f1) == deep_to_string(f2));
// spawn a testee that receives two messages of user-defined type // spawn a testee that receives two messages of user-defined type
auto t = sys.spawn(testee, 2u); auto t = sys.spawn(testee, 2u);
scoped_actor self{sys}; scoped_actor self{sys};
......
// showcases how to add custom message types to CAF // showcases how to add custom message types to CAF
// if friend access for serialization is available // if friend access for serialization is available
#include <utility>
#include <iostream> #include <iostream>
#include <utility>
#include "caf/all.hpp" #include "caf/all.hpp"
...@@ -47,8 +47,8 @@ public: ...@@ -47,8 +47,8 @@ public:
} }
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, foo& x) { friend bool inspect(Inspector& f, foo& x) {
return f(meta::type_name("foo"), x.a_, x.b_); return f.object(x).fields(f.field("a", x.a_), f.field("b", x.b_));
} }
private: private:
...@@ -57,11 +57,7 @@ private: ...@@ -57,11 +57,7 @@ private:
}; };
behavior testee(event_based_actor* self) { behavior testee(event_based_actor* self) {
return { return {[=](const foo& x) { aout(self) << deep_to_string(x) << endl; }};
[=](const foo& x) {
aout(self) << to_string(x) << endl;
}
};
} }
void caf_main(actor_system& sys) { void caf_main(actor_system& sys) {
......
...@@ -83,25 +83,25 @@ scope_guard<Fun> make_scope_guard(Fun f) { ...@@ -83,25 +83,25 @@ scope_guard<Fun> make_scope_guard(Fun f) {
// --(rst-inspect-begin)-- // --(rst-inspect-begin)--
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo& x) { bool inspect(Inspector& f, foo& x) {
if constexpr (Inspector::reads_state) { auto get_a = [&x] { return x.a(); };
return f(meta::type_name("foo"), x.a(), x.b()); auto set_a = [&x](int val) {
} else { x.set_a(val);
int a; return true;
int b; };
// write back to x at scope exit auto get_b = [&x] { return x.b(); };
auto g = make_scope_guard([&] { auto set_b = [&x](int val) {
x.set_a(a); x.set_b(val);
x.set_b(b); return true;
}); };
return f(meta::type_name("foo"), a, b); return f.object(x).fields(f.field("a", get_a, set_a),
} f.field("b", get_b, set_b));
} }
// --(rst-inspect-end)-- // --(rst-inspect-end)--
behavior testee(event_based_actor* self) { behavior testee(event_based_actor* self) {
return { return {
[=](const foo& x) { aout(self) << to_string(x) << endl; }, [=](const foo& x) { aout(self) << deep_to_string(x) << endl; },
}; };
} }
......
...@@ -3,10 +3,6 @@ ...@@ -3,10 +3,6 @@
* for both the blocking and the event-based API. * * for both the blocking and the event-based API. *
\******************************************************************************/ \******************************************************************************/
// This file is partially included in the manual, do not modify
// without updating the references in the *.tex files!
// Manual references: lines 18-44, and 49-50 (Actor.tex)
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
...@@ -16,32 +12,45 @@ using std::cout; ...@@ -16,32 +12,45 @@ using std::cout;
using std::endl; using std::endl;
using namespace caf; using namespace caf;
using cell // --(rst-cell-begin)--
= typed_actor<result<void>(put_atom, int32_t), result<int32_t>(get_atom)>; using cell = typed_actor<
// 'put' updates the value of the cell.
result<void>(put_atom, int32_t),
// 'get' queries the value of the cell.
result<int32_t>(get_atom)>;
struct cell_state { struct cell_state {
int32_t value = 0; int32_t value = 0;
static inline const char* name = "example.cell";
}; };
cell::behavior_type type_checked_cell(cell::stateful_pointer<cell_state> self) { cell::behavior_type type_checked_cell(cell::stateful_pointer<cell_state> self) {
return {[=](put_atom, int32_t val) { self->state.value = val; }, return {
[=](get_atom) { return self->state.value; }}; [=](put_atom, int32_t val) { self->state.value = val; },
[=](get_atom) { return self->state.value; },
};
} }
behavior unchecked_cell(stateful_actor<cell_state>* self) { behavior unchecked_cell(stateful_actor<cell_state>* self) {
return {[=](put_atom, int32_t val) { self->state.value = val; }, return {
[=](get_atom) { return self->state.value; }}; [=](put_atom, int32_t val) { self->state.value = val; },
[=](get_atom) { return self->state.value; },
};
} }
// --(rst-cell-end)--
void caf_main(actor_system& system) { void caf_main(actor_system& system) {
// create one cell for each implementation // --(rst-spawn-cell-end)--
// Create one cell for each implementation.
auto cell1 = system.spawn(type_checked_cell); auto cell1 = system.spawn(type_checked_cell);
auto cell2 = system.spawn(unchecked_cell); auto cell2 = system.spawn(unchecked_cell);
// --(rst-spawn-cell-end)--
auto f = make_function_view(cell1); auto f = make_function_view(cell1);
cout << "cell value: " << f(get_atom_v) << endl; cout << "cell value: " << f(get_atom_v) << endl;
f(put_atom_v, 20); f(put_atom_v, 20);
cout << "cell value (after setting to 20): " << f(get_atom_v) << endl; cout << "cell value (after setting to 20): " << f(get_atom_v) << endl;
// get an unchecked cell and send it some garbage // Get an unchecked cell and send it some garbage. Triggers an "unexpected
// message" error.
anon_send(cell2, "hello there!"); anon_send(cell2, "hello there!");
} }
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
} }
behavior make_behavior() override { behavior make_behavior() override {
assert(size_ < 2); assert(size_ >= 2);
return empty_; return empty_;
} }
......
...@@ -68,6 +68,8 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -68,6 +68,8 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/config_option_adder.cpp src/config_option_adder.cpp
src/config_option_set.cpp src/config_option_set.cpp
src/config_value.cpp src/config_value.cpp
src/config_value_reader.cpp
src/config_value_writer.cpp
src/credit_controller.cpp src/credit_controller.cpp
src/decorator/sequencer.cpp src/decorator/sequencer.cpp
src/default_attachable.cpp src/default_attachable.cpp
...@@ -90,6 +92,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -90,6 +92,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/detail/parse.cpp src/detail/parse.cpp
src/detail/parser/chars.cpp src/detail/parser/chars.cpp
src/detail/pretty_type_name.cpp src/detail/pretty_type_name.cpp
src/detail/print.cpp
src/detail/private_thread.cpp src/detail/private_thread.cpp
src/detail/ripemd_160.cpp src/detail/ripemd_160.cpp
src/detail/serialized_size.cpp src/detail/serialized_size.cpp
...@@ -105,7 +108,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -105,7 +108,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/detail/token_based_credit_controller.cpp src/detail/token_based_credit_controller.cpp
src/detail/token_based_credit_controller.cpp src/detail/token_based_credit_controller.cpp
src/detail/type_id_list_builder.cpp src/detail/type_id_list_builder.cpp
src/detail/uri_impl.cpp
src/downstream_manager.cpp src/downstream_manager.cpp
src/downstream_manager_base.cpp src/downstream_manager_base.cpp
src/error.cpp src/error.cpp
...@@ -127,6 +129,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -127,6 +129,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/ipv6_address.cpp src/ipv6_address.cpp
src/ipv6_endpoint.cpp src/ipv6_endpoint.cpp
src/ipv6_subnet.cpp src/ipv6_subnet.cpp
src/load_inspector.cpp
src/local_actor.cpp src/local_actor.cpp
src/logger.cpp src/logger.cpp
src/mailbox_element.cpp src/mailbox_element.cpp
...@@ -150,6 +153,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -150,6 +153,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/replies_to.cpp src/replies_to.cpp
src/response_promise.cpp src/response_promise.cpp
src/resumable.cpp src/resumable.cpp
src/save_inspector.cpp
src/scheduled_actor.cpp src/scheduled_actor.cpp
src/scheduler/abstract_coordinator.cpp src/scheduler/abstract_coordinator.cpp
src/scheduler/test_coordinator.cpp src/scheduler/test_coordinator.cpp
...@@ -175,6 +179,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -175,6 +179,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/timestamp.cpp src/timestamp.cpp
src/tracing_data.cpp src/tracing_data.cpp
src/tracing_data_factory.cpp src/tracing_data_factory.cpp
src/type_id.cpp
src/type_id_list.cpp src/type_id_list.cpp
src/uri.cpp src/uri.cpp
src/uri_builder.cpp src/uri_builder.cpp
...@@ -198,6 +203,7 @@ endif() ...@@ -198,6 +203,7 @@ endif()
add_executable(caf-core-test add_executable(caf-core-test
test/core-test.cpp test/core-test.cpp
test/nasty.cpp
$<TARGET_OBJECTS:libcaf_core_obj>) $<TARGET_OBJECTS:libcaf_core_obj>)
caf_core_set_default_properties(caf-core-test) caf_core_set_default_properties(caf-core-test)
...@@ -227,7 +233,8 @@ caf_add_test_suites(caf-core-test ...@@ -227,7 +233,8 @@ caf_add_test_suites(caf-core-test
config_option config_option
config_option_set config_option_set
config_value config_value
config_value_adaptor config_value_reader
config_value_writer
const_typed_message_view const_typed_message_view
constructor_attach constructor_attach
continuous_streaming continuous_streaming
...@@ -265,7 +272,6 @@ caf_add_test_suites(caf-core-test ...@@ -265,7 +272,6 @@ caf_add_test_suites(caf-core-test
fused_downstream_manager fused_downstream_manager
handles handles
hash.fnv hash.fnv
inspector
intrusive.drr_cached_queue intrusive.drr_cached_queue
intrusive.drr_queue intrusive.drr_queue
intrusive.fifo_inbox intrusive.fifo_inbox
...@@ -280,10 +286,10 @@ caf_add_test_suites(caf-core-test ...@@ -280,10 +286,10 @@ caf_add_test_suites(caf-core-test
ipv6_address ipv6_address
ipv6_endpoint ipv6_endpoint
ipv6_subnet ipv6_subnet
load_inspector
local_group local_group
logger logger
mailbox_element mailbox_element
make_config_value_field
message message
message_builder message_builder
message_id message_id
...@@ -302,6 +308,7 @@ caf_add_test_suites(caf-core-test ...@@ -302,6 +308,7 @@ caf_add_test_suites(caf-core-test
policy.select_any policy.select_any
request_timeout request_timeout
result result
save_inspector
selective_streaming selective_streaming
serial_reply serial_reply
serialization serialization
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <string> #include <string>
#include "caf/abstract_channel.hpp" #include "caf/abstract_channel.hpp"
#include "caf/actor.hpp"
#include "caf/actor_addr.hpp" #include "caf/actor_addr.hpp"
#include "caf/attachable.hpp" #include "caf/attachable.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
...@@ -46,12 +47,6 @@ public: ...@@ -46,12 +47,6 @@ public:
// -- pure virtual member functions ------------------------------------------ // -- pure virtual member functions ------------------------------------------
/// Serialize this group to `sink`.
virtual error save(serializer& sink) const = 0;
/// Serialize this group to `sink`.
virtual error_code<sec> save(binary_serializer& sink) const = 0;
/// Subscribes `who` to this group and returns `true` on success /// Subscribes `who` to this group and returns `true` on success
/// or `false` if `who` is already subscribed. /// or `false` if `who` is already subscribed.
virtual bool subscribe(strong_actor_ptr who) = 0; virtual bool subscribe(strong_actor_ptr who) = 0;
...@@ -64,22 +59,27 @@ public: ...@@ -64,22 +59,27 @@ public:
// -- observers -------------------------------------------------------------- // -- observers --------------------------------------------------------------
/// Returns the parent module.
group_module& module() const {
return parent_;
}
/// Returns the hosting system. /// Returns the hosting system.
actor_system& system() const { actor_system& system() const {
return system_; return system_;
} }
/// Returns the parent module.
group_module& module() const {
return parent_;
}
/// Returns a string representation of the group identifier, e.g., /// Returns a string representation of the group identifier, e.g.,
/// "224.0.0.1" for IPv4 multicast or a user-defined string for local groups. /// "224.0.0.1" for IPv4 multicast or a user-defined string for local groups.
const std::string& identifier() const { const std::string& identifier() const {
return identifier_; return identifier_;
} }
/// @private
const actor& dispatcher() {
return dispatcher_;
}
protected: protected:
abstract_group(group_module& mod, std::string id, node_id nid); abstract_group(group_module& mod, std::string id, node_id nid);
...@@ -87,6 +87,7 @@ protected: ...@@ -87,6 +87,7 @@ protected:
group_module& parent_; group_module& parent_;
std::string identifier_; std::string identifier_;
node_id origin_; node_id origin_;
actor dispatcher_;
}; };
/// A smart pointer type that manages instances of {@link group}. /// A smart pointer type that manages instances of {@link group}.
......
...@@ -147,7 +147,7 @@ public: ...@@ -147,7 +147,7 @@ public:
} }
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, actor& x) { friend bool inspect(Inspector& f, actor& x) {
return inspect(f, x.ptr_); return inspect(f, x.ptr_);
} }
......
...@@ -110,7 +110,7 @@ public: ...@@ -110,7 +110,7 @@ public:
} }
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, actor_addr& x) { friend bool inspect(Inspector& f, actor_addr& x) {
return inspect(f, x.ptr_); return inspect(f, x.ptr_);
} }
......
...@@ -25,10 +25,6 @@ ...@@ -25,10 +25,6 @@
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/intrusive_ptr.hpp" #include "caf/intrusive_ptr.hpp"
#include "caf/meta/load_callback.hpp"
#include "caf/meta/omittable_if_none.hpp"
#include "caf/meta/save_callback.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/node_id.hpp" #include "caf/node_id.hpp"
#include "caf/weak_intrusive_ptr.hpp" #include "caf/weak_intrusive_ptr.hpp"
...@@ -97,7 +93,7 @@ public: ...@@ -97,7 +93,7 @@ public:
static_assert(sizeof(std::atomic<size_t>) == sizeof(void*), static_assert(sizeof(std::atomic<size_t>) == sizeof(void*),
"std::atomic not lockfree on this platform"); "std::atomic not lockfree on this platform");
static_assert(sizeof(intrusive_ptr<node_id::data>) == sizeof(void*), static_assert(sizeof(intrusive_ptr<int>) == sizeof(int*),
"intrusive_ptr<T> and T* have different size"); "intrusive_ptr<T> and T* have different size");
static_assert(sizeof(node_id) == sizeof(void*), static_assert(sizeof(node_id) == sizeof(void*),
...@@ -205,25 +201,38 @@ CAF_CORE_EXPORT std::string to_string(const weak_actor_ptr& x); ...@@ -205,25 +201,38 @@ CAF_CORE_EXPORT std::string to_string(const weak_actor_ptr& x);
CAF_CORE_EXPORT void append_to_string(std::string& x, const weak_actor_ptr& y); CAF_CORE_EXPORT void append_to_string(std::string& x, const weak_actor_ptr& y);
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, strong_actor_ptr& x) { bool inspect(Inspector& f, strong_actor_ptr& x) {
actor_id aid = 0; actor_id aid = 0;
node_id nid; node_id nid;
if (x) { if constexpr (!Inspector::is_loading) {
aid = x->aid; if (x) {
nid = x->nid; aid = x->aid;
nid = x->nid;
}
} }
auto load = [&] { return load_actor(x, context_of(&f), aid, nid); }; auto load_cb = [&] { return load_actor(x, context_of(&f), aid, nid); };
auto save = [&] { return save_actor(x, context_of(&f), aid, nid); }; auto save_cb = [&] { return save_actor(x, context_of(&f), aid, nid); };
return f(meta::type_name("actor"), aid, meta::omittable_if_none(), nid, return f.object(x)
meta::load_callback(load), meta::save_callback(save)); .pretty_name("actor")
.on_load(load_cb)
.on_save(save_cb)
.fields(f.field("id", aid), f.field("node", nid));
} }
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, weak_actor_ptr& x) { bool inspect(Inspector& f, weak_actor_ptr& x) {
// inspect as strong pointer, then write back to weak pointer on save // Inspect as strong pointer, then write back to weak pointer on save.
auto tmp = x.lock(); if constexpr (Inspector::is_loading) {
auto load = [&] { x.reset(tmp.get()); }; strong_actor_ptr tmp;
return f(tmp, meta::load_callback(load)); if (inspect(f, tmp)) {
x.reset(tmp.get());
return true;
}
return false;
} else {
auto tmp = x.lock();
return inspect(f, tmp);
}
} }
} // namespace caf } // namespace caf
......
...@@ -75,8 +75,8 @@ struct typed_mpi_access<result<Out...>(In...)> { ...@@ -75,8 +75,8 @@ struct typed_mpi_access<result<Out...>(In...)> {
std::string operator()() const { std::string operator()() const {
static_assert(sizeof...(In) > 0, "typed MPI without inputs"); static_assert(sizeof...(In) > 0, "typed MPI without inputs");
static_assert(sizeof...(Out) > 0, "typed MPI without outputs"); static_assert(sizeof...(Out) > 0, "typed MPI without outputs");
std::vector<std::string> inputs{type_name_v<In>...}; std::vector<std::string> inputs{to_string(type_name_v<In>)...};
std::vector<std::string> outputs1{type_name_v<Out>...}; std::vector<std::string> outputs1{to_string(type_name_v<Out>)...};
std::string result = "("; std::string result = "(";
result += join(inputs, ","); result += join(inputs, ",");
result += ") -> ("; result += ") -> (";
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include "caf/dictionary.hpp" #include "caf/dictionary.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/is_typed_actor.hpp" #include "caf/is_typed_actor.hpp"
#include "caf/named_actor_config.hpp"
#include "caf/settings.hpp" #include "caf/settings.hpp"
#include "caf/stream.hpp" #include "caf/stream.hpp"
#include "caf/thread_hook.hpp" #include "caf/thread_hook.hpp"
...@@ -75,8 +74,6 @@ public: ...@@ -75,8 +74,6 @@ public:
using string_list = std::vector<std::string>; using string_list = std::vector<std::string>;
using named_actor_config_map = hash_map<std::string, named_actor_config>;
using opt_group = config_option_adder; using opt_group = config_option_adder;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
...@@ -247,9 +244,6 @@ public: ...@@ -247,9 +244,6 @@ public:
// -- utility for caf-run ---------------------------------------------------- // -- utility for caf-run ----------------------------------------------------
// Config parameter for individual actor types.
named_actor_config_map named_actor_configs;
int (*slave_mode_fun)(actor_system&, const actor_system_config&); int (*slave_mode_fun)(actor_system&, const actor_system_config&);
// -- default error rendering functions -------------------------------------- // -- default error rendering functions --------------------------------------
......
...@@ -48,16 +48,12 @@ ...@@ -48,16 +48,12 @@
#include "caf/config_option.hpp" #include "caf/config_option.hpp"
#include "caf/config_option_adder.hpp" #include "caf/config_option_adder.hpp"
#include "caf/config_value.hpp" #include "caf/config_value.hpp"
#include "caf/config_value_adaptor.hpp" #include "caf/config_value_reader.hpp"
#include "caf/config_value_adaptor_access.hpp" #include "caf/config_value_writer.hpp"
#include "caf/config_value_adaptor_field.hpp"
#include "caf/config_value_field.hpp"
#include "caf/config_value_object_access.hpp"
#include "caf/const_typed_message_view.hpp" #include "caf/const_typed_message_view.hpp"
#include "caf/deep_to_string.hpp" #include "caf/deep_to_string.hpp"
#include "caf/defaults.hpp" #include "caf/defaults.hpp"
#include "caf/deserializer.hpp" #include "caf/deserializer.hpp"
#include "caf/detail/config_value_adaptor_field_impl.hpp"
#include "caf/downstream_msg.hpp" #include "caf/downstream_msg.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/event_based_actor.hpp" #include "caf/event_based_actor.hpp"
...@@ -70,12 +66,10 @@ ...@@ -70,12 +66,10 @@
#include "caf/fused_downstream_manager.hpp" #include "caf/fused_downstream_manager.hpp"
#include "caf/group.hpp" #include "caf/group.hpp"
#include "caf/hash/fnv.hpp" #include "caf/hash/fnv.hpp"
#include "caf/index_mapping.hpp"
#include "caf/init_global_meta_objects.hpp" #include "caf/init_global_meta_objects.hpp"
#include "caf/local_actor.hpp" #include "caf/local_actor.hpp"
#include "caf/logger.hpp" #include "caf/logger.hpp"
#include "caf/make_config_option.hpp" #include "caf/make_config_option.hpp"
#include "caf/make_config_value_field.hpp"
#include "caf/may_have_timeout.hpp" #include "caf/may_have_timeout.hpp"
#include "caf/memory_managed.hpp" #include "caf/memory_managed.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
...@@ -106,7 +100,6 @@ ...@@ -106,7 +100,6 @@
#include "caf/term.hpp" #include "caf/term.hpp"
#include "caf/thread_hook.hpp" #include "caf/thread_hook.hpp"
#include "caf/timeout_definition.hpp" #include "caf/timeout_definition.hpp"
#include "caf/to_string.hpp"
#include "caf/tracing_data.hpp" #include "caf/tracing_data.hpp"
#include "caf/tracing_data_factory.hpp" #include "caf/tracing_data_factory.hpp"
#include "caf/type_id.hpp" #include "caf/type_id.hpp"
......
...@@ -26,21 +26,17 @@ ...@@ -26,21 +26,17 @@
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/error_code.hpp" #include "caf/error_code.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/load_inspector_base.hpp"
#include "caf/sec.hpp" #include "caf/sec.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
#include "caf/write_inspector.hpp"
namespace caf { namespace caf {
/// Deserializes objects from sequence of bytes. /// Deserializes objects from sequence of bytes.
class CAF_CORE_EXPORT binary_deserializer class CAF_CORE_EXPORT binary_deserializer
: public write_inspector<binary_deserializer> { : public load_inspector_base<binary_deserializer> {
public: public:
// -- member types -----------------------------------------------------------
using result_type = error_code<sec>;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
template <class Container> template <class Container>
...@@ -87,7 +83,7 @@ public: ...@@ -87,7 +83,7 @@ public:
/// Jumps `num_bytes` forward. /// Jumps `num_bytes` forward.
/// @pre `num_bytes <= remaining()` /// @pre `num_bytes <= remaining()`
void skip(size_t num_bytes) noexcept; void skip(size_t num_bytes);
/// Assigns a new input. /// Assigns a new input.
void reset(span<const byte> bytes) noexcept; void reset(span<const byte> bytes) noexcept;
...@@ -102,56 +98,103 @@ public: ...@@ -102,56 +98,103 @@ public:
return end_; return end_;
} }
static constexpr bool has_human_readable_format() noexcept {
return false;
}
// -- overridden member functions -------------------------------------------- // -- overridden member functions --------------------------------------------
result_type begin_object(type_id_t& type); bool fetch_next_object_type(type_id_t& type) noexcept;
result_type end_object() noexcept; constexpr bool begin_object(string_view) noexcept {
return ok;
}
result_type begin_sequence(size_t& list_size) noexcept; constexpr bool end_object() noexcept {
return ok;
}
result_type end_sequence() noexcept; constexpr bool begin_field(string_view) noexcept {
return true;
}
result_type apply(bool&) noexcept; bool begin_field(string_view name, bool& is_present) noexcept;
result_type apply(byte&) noexcept; bool begin_field(string_view name, span<const type_id_t> types,
size_t& index) noexcept;
result_type apply(int8_t&) noexcept; bool begin_field(string_view name, bool& is_present,
span<const type_id_t> types, size_t& index) noexcept;
result_type apply(uint8_t&) noexcept; constexpr bool end_field() {
return ok;
}
result_type apply(int16_t&) noexcept; constexpr bool begin_tuple(size_t) noexcept {
return ok;
}
result_type apply(uint16_t&) noexcept; constexpr bool end_tuple() noexcept {
return ok;
}
result_type apply(int32_t&) noexcept; constexpr bool begin_key_value_pair() noexcept {
return ok;
}
result_type apply(uint32_t&) noexcept; constexpr bool end_key_value_pair() noexcept {
return ok;
}
result_type apply(int64_t&) noexcept; bool begin_sequence(size_t& list_size) noexcept;
result_type apply(uint64_t&) noexcept; constexpr bool end_sequence() noexcept {
return ok;
}
result_type apply(float&) noexcept; bool begin_associative_array(size_t& size) noexcept {
return begin_sequence(size);
}
result_type apply(double&) noexcept; bool end_associative_array() noexcept {
return end_sequence();
}
result_type apply(long double&); bool value(bool& x) noexcept;
result_type apply(span<byte>) noexcept; bool value(byte& x) noexcept;
result_type apply(std::string&); bool value(uint8_t& x) noexcept;
result_type apply(std::u16string&); bool value(int8_t& x) noexcept;
result_type apply(std::u32string&); bool value(int16_t& x) noexcept;
template <class Enum, class = std::enable_if_t<std::is_enum<Enum>::value>> bool value(uint16_t& x) noexcept;
auto apply(Enum& x) noexcept {
return apply(reinterpret_cast<std::underlying_type_t<Enum>&>(x)); bool value(int32_t& x) noexcept;
}
bool value(uint32_t& x) noexcept;
bool value(int64_t& x) noexcept;
bool value(uint64_t& x) noexcept;
bool value(float& x) noexcept;
bool value(double& x) noexcept;
bool value(long double& x);
bool value(std::string& x);
bool value(std::u16string& x);
bool value(std::u32string& x);
bool value(span<byte> x) noexcept;
result_type apply(std::vector<bool>& xs); bool value(std::vector<bool>& x);
private: private:
explicit binary_deserializer(actor_system& sys) noexcept; explicit binary_deserializer(actor_system& sys) noexcept;
......
...@@ -20,31 +20,23 @@ ...@@ -20,31 +20,23 @@
#include <cstddef> #include <cstddef>
#include <string> #include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector> #include <vector>
#include "caf/byte.hpp" #include "caf/byte.hpp"
#include "caf/byte_buffer.hpp" #include "caf/byte_buffer.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/squashed_int.hpp"
#include "caf/error_code.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/read_inspector.hpp" #include "caf/save_inspector_base.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
namespace caf { namespace caf {
/// Serializes objects into a sequence of bytes. /// Serializes objects into a sequence of bytes.
class CAF_CORE_EXPORT binary_serializer class CAF_CORE_EXPORT binary_serializer
: public read_inspector<binary_serializer> { : public save_inspector_base<binary_serializer> {
public: public:
// -- member types ----------------------------------------------------------- // -- member types -----------------------------------------------------------
using result_type = error_code<sec>;
using container_type = byte_buffer; using container_type = byte_buffer;
using value_type = byte; using value_type = byte;
...@@ -81,6 +73,10 @@ public: ...@@ -81,6 +73,10 @@ public:
return write_pos_; return write_pos_;
} }
static constexpr bool has_human_readable_format() noexcept {
return false;
}
// -- position management ---------------------------------------------------- // -- position management ----------------------------------------------------
/// Sets the write position to `offset`. /// Sets the write position to `offset`.
...@@ -95,52 +91,96 @@ public: ...@@ -95,52 +91,96 @@ public:
// -- interface functions ---------------------------------------------------- // -- interface functions ----------------------------------------------------
error_code<sec> begin_object(type_id_t type); bool inject_next_object_type(type_id_t type);
error_code<sec> end_object();
error_code<sec> begin_sequence(size_t list_size); constexpr bool begin_object(string_view) {
return ok;
error_code<sec> end_sequence(); }
void apply(byte x); constexpr bool end_object() {
return ok;
}
void apply(uint8_t x); constexpr bool begin_field(string_view) noexcept {
return ok;
}
void apply(uint16_t x); bool begin_field(string_view, bool is_present);
void apply(uint32_t x); bool begin_field(string_view, span<const type_id_t> types, size_t index);
void apply(uint64_t x); bool begin_field(string_view, bool is_present, span<const type_id_t> types,
size_t index);
void apply(float x); constexpr bool end_field() {
return ok;
}
void apply(double x); constexpr bool begin_tuple(size_t) {
return ok;
}
void apply(long double x); constexpr bool end_tuple() {
return ok;
}
void apply(string_view x); constexpr bool begin_key_value_pair() {
return ok;
}
void apply(const std::u16string& x); constexpr bool end_key_value_pair() {
return ok;
}
void apply(const std::u32string& x); bool begin_sequence(size_t list_size);
void apply(span<const byte> x); constexpr bool end_sequence() {
return ok;
}
template <class T> bool begin_associative_array(size_t size) {
std::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value> return begin_sequence(size);
apply(T x) {
using unsigned_type = std::make_unsigned_t<T>;
using squashed_unsigned_type = detail::squashed_int_t<unsigned_type>;
return apply(static_cast<squashed_unsigned_type>(x));
} }
template <class Enum> bool end_associative_array() {
std::enable_if_t<std::is_enum<Enum>::value> apply(Enum x) { return end_sequence();
return apply(static_cast<std::underlying_type_t<Enum>>(x));
} }
void apply(const std::vector<bool>& x); bool value(byte x);
bool value(bool x);
bool value(int8_t x);
bool value(uint8_t x);
bool value(int16_t x);
bool value(uint16_t x);
bool value(int32_t x);
bool value(uint32_t x);
bool value(int64_t x);
bool value(uint64_t x);
bool value(float x);
bool value(double x);
bool value(long double x);
bool value(string_view x);
bool value(const std::u16string& x);
bool value(const std::u32string& x);
bool value(span<const byte> x);
bool value(const std::vector<bool>& x);
private: private:
/// Stores the serialized output. /// Stores the serialized output.
......
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include <array>
#include <tuple>
#include <type_traits>
#include "caf/config_value_adaptor_field.hpp"
#include "caf/detail/config_value_adaptor_field_impl.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/optional.hpp"
#include "caf/span.hpp"
#include "caf/string_view.hpp"
namespace caf {
/// Interfaces between a user-defined type and CAF config values by going
/// through intermediate values.
template <class... Ts>
class config_value_adaptor {
public:
using value_type = std::tuple<Ts...>;
using indices = typename detail::il_indices<value_type>::type;
using fields_tuple =
typename detail::select_adaptor_fields<value_type, indices>::type;
using array_type = std::array<config_value_field<value_type>*, sizeof...(Ts)>;
template <class U,
class = detail::enable_if_t<
!std::is_same<detail::decay_t<U>, config_value_adaptor>::value>,
class... Us>
config_value_adaptor(U&& x, Us&&... xs)
: fields_(
make_fields(indices{}, std::forward<U>(x), std::forward<Us>(xs)...)) {
init(indices{});
}
config_value_adaptor(config_value_adaptor&&) = default;
span<typename array_type::value_type> fields() {
return make_span(ptr_fields_);
}
private:
// TODO: This is a workaround for GCC <= 5 because initializing fields_
// directly from (xs...) fails. Remove when moving on to newer
// compilers.
template <long... Pos, class... Us>
fields_tuple make_fields(detail::int_list<Pos...>, Us&&... xs) {
return std::make_tuple(
detail::config_value_adaptor_field_impl<value_type, Pos>(
std::forward<Us>(xs))...);
}
template <long... Pos>
void init(detail::int_list<Pos...>) {
ptr_fields_ = array_type{{&std::get<Pos>(fields_)...}};
}
fields_tuple fields_;
array_type ptr_fields_;
};
template <class... Ts>
config_value_adaptor<typename Ts::value_type...>
make_config_value_adaptor(Ts... fields) {
return {std::move(fields)...};
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include "caf/optional.hpp"
#include "caf/string_view.hpp"
namespace caf {
/// Describes a field of type T of an adaptor.
template <class T>
struct config_value_adaptor_field {
/// Type of the field.
using value_type = T;
/// Predicate function for verifying user input.
using predicate_function = bool (*)(const value_type&);
/// Name of the field in configuration files and on the CLI.
string_view name;
/// If set, makes the field optional in configuration files and on the CLI by
/// assigning the default whenever the user provides no value.
optional<value_type> default_value;
/// If set, makes the field only accept values that pass this predicate.
predicate_function predicate;
};
/// Convenience function for creating a `config_value_adaptor_field`.
/// @param name name of the field in configuration files and on the CLI.
/// @param default_value if set, provides a fallback value if the user does not
/// provide a value.
/// @param predicate if set, restricts what values the field accepts.
/// @returns a `config_value_adaptor_field` object, constructed from given
/// arguments.
/// @relates config_value_adaptor_field
template <class T>
config_value_adaptor_field<T>
make_config_value_adaptor_field(string_view name,
optional<T> default_value = none,
bool (*predicate)(const T&) = nullptr) {
return {name, std::move(default_value), predicate};
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include "caf/config_value.hpp"
#include "caf/config_value_field.hpp"
namespace caf {
/// Enables user-defined types in config files and on the CLI by converting
/// them to and from `config_value::dictionary`.
///
/// ~~
/// struct trait {
/// using object_type = ...;
///
/// static string_value type_name();
///
/// static span<config_value_field<object_type>*> fields();
/// };
/// ~~
template <class Trait>
struct config_value_object_access {
using object_type = typename Trait::object_type;
static std::string type_name() {
return Trait::type_name();
}
static bool extract(const config_value* src, object_type* dst) {
auto dict = caf::get_if<config_value::dictionary>(src);
if (!dict)
return false;
for (auto field : Trait::fields()) {
if (auto value = caf::get_if(dict, field->name())) {
if (dst) {
if (!field->set(*dst, *value))
return false;
} else {
if (!field->valid_input(*value))
return false;
}
} else {
if (!field->has_default())
return false;
if (dst)
field->set_default(*dst);
}
}
return true;
}
static bool is(const config_value& x) {
return extract(&x, nullptr);
}
static optional<object_type> get_if(const config_value* x) {
object_type result;
if (extract(x, &result))
return result;
return none;
}
static object_type get(const config_value& x) {
auto result = get_if(&x);
if (!result)
CAF_RAISE_ERROR("config_value does not contain requested object");
return std::move(*result);
}
static config_value::dictionary convert(const object_type& x) {
config_value::dictionary result;
for (auto field : Trait::fields())
result.emplace(field->name(), field->get(x));
return result;
}
template <class Nested>
static void parse_cli(string_parser_state& ps, object_type& x, Nested) {
using field_type = config_value_field<object_type>;
std::vector<field_type*> parsed_fields;
auto got = [&](field_type* f) {
auto e = parsed_fields.end();
return std::find(parsed_fields.begin(), e, f) != e;
};
auto push = [&](field_type* f) {
if (got(f))
return false;
parsed_fields.emplace_back(f);
return true;
};
auto finalize = [&] {
for (auto field : Trait::fields()) {
if (!got(field)) {
if (field->has_default()) {
field->set_default(x);
} else {
ps.code = pec::missing_field;
return;
}
}
}
ps.skip_whitespaces();
ps.code = ps.at_end() ? pec::success : pec::trailing_character;
};
auto fs = Trait::fields();
if (!ps.consume('{')) {
ps.code = pec::unexpected_character;
return;
}
using string_access = select_config_value_access_t<std::string>;
config_value::dictionary result;
do {
if (ps.consume('}')) {
finalize();
return;
}
std::string field_name;
string_access::parse_cli(ps, field_name, nested_cli_parsing);
if (ps.code > pec::trailing_character)
return;
if (!ps.consume('=')) {
ps.code = ps.at_end() ? pec::unexpected_eof : pec::unexpected_character;
return;
}
auto predicate = [&](config_value_field<object_type>* x) {
return x->name() == field_name;
};
auto f = std::find_if(fs.begin(), fs.end(), predicate);
if (f == fs.end()) {
ps.code = pec::invalid_field_name;
return;
}
auto fptr = *f;
if (!push(fptr)) {
ps.code = pec::repeated_field_name;
return;
}
fptr->parse_cli(ps, x, true);
if (ps.code > pec::trailing_character)
return;
if (ps.at_end()) {
ps.code = pec::unexpected_eof;
return;
}
result[fptr->name()] = fptr->get(x);
} while (ps.consume(','));
if (!ps.consume('}')) {
ps.code = ps.at_end() ? pec::unexpected_eof : pec::unexpected_character;
return;
}
finalize();
}
};
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include "caf/deserializer.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp"
#include <stack>
#include <vector>
namespace caf {
/// Extracts objects from a @ref config_value.
class CAF_CORE_EXPORT config_value_reader final : public deserializer {
public:
// -- member types------------------------------------------------------------
using super = deserializer;
using key_ptr = const std::string*;
struct absent_field {};
struct sequence {
using list_pointer = const std::vector<config_value>*;
size_t index;
list_pointer ls;
explicit sequence(list_pointer ls) : index(0), ls(ls) {
// nop
}
bool at_end() const noexcept;
const config_value& current();
void advance() {
++index;
}
};
struct associative_array {
settings::const_iterator pos;
settings::const_iterator end;
bool at_end() const noexcept;
const std::pair<const std::string, config_value>& current();
};
using value_type = variant<const settings*, const config_value*, key_ptr,
absent_field, sequence, associative_array>;
using stack_type = std::stack<value_type, std::vector<value_type>>;
// -- constructors, destructors, and assignment operators --------------------
config_value_reader(const config_value* input, actor_system& sys)
: super(sys) {
st_.push(input);
has_human_readable_format_ = true;
}
config_value_reader(const config_value* input, execution_unit* ctx)
: super(ctx) {
st_.push(input);
has_human_readable_format_ = true;
}
explicit config_value_reader(const config_value* input)
: config_value_reader(input, nullptr) {
// nop
}
~config_value_reader() override;
// -- stack access -----------------------------------------------------------
value_type& top() {
return st_.top();
}
void pop() {
return st_.pop();
}
// -- interface functions ----------------------------------------------------
bool fetch_next_object_type(type_id_t& type) override;
bool begin_object(string_view name) override;
bool end_object() override;
bool begin_field(string_view) override;
bool begin_field(string_view name, bool& is_present) override;
bool begin_field(string_view name, span<const type_id_t> types,
size_t& index) override;
bool begin_field(string_view name, bool& is_present,
span<const type_id_t> types, size_t& index) override;
bool end_field() override;
bool begin_tuple(size_t size) override;
bool end_tuple() override;
bool begin_key_value_pair() override;
bool end_key_value_pair() override;
bool begin_sequence(size_t& size) override;
bool end_sequence() override;
bool begin_associative_array(size_t& size) override;
bool end_associative_array() override;
bool value(bool& x) override;
bool value(int8_t& x) override;
bool value(uint8_t& x) override;
bool value(int16_t& x) override;
bool value(uint16_t& x) override;
bool value(int32_t& x) override;
bool value(uint32_t& x) override;
bool value(int64_t& x) override;
bool value(uint64_t& x) override;
bool value(float& x) override;
bool value(double& x) override;
bool value(long double& x) override;
bool value(std::string& x) override;
bool value(std::u16string& x) override;
bool value(std::u32string& x) override;
bool value(span<byte> x) override;
private:
bool fetch_object_type(const settings* obj, type_id_t& type);
stack_type st_;
};
} // namespace caf
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework * * | |___ / ___ \| _| Framework *
* \____/_/ \_|_| * * \____/_/ \_|_| *
* * * *
* Copyright 2011-2018 Dominik Charousset * * Copyright 2011-2020 Dominik Charousset *
* * * *
* Distributed under the terms and conditions of the BSD 3-Clause License or * * 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 * * (at your option) under the terms and conditions of the Boost Software *
...@@ -18,88 +18,127 @@ ...@@ -18,88 +18,127 @@
#pragma once #pragma once
#include <atomic>
#include <cstdint>
#include <string>
#include <utility>
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/error.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/meta/load_callback.hpp" #include "caf/serializer.hpp"
#include "caf/ref_counted.hpp"
#include "caf/string_view.hpp" #include <stack>
#include "caf/uri.hpp" #include <vector>
namespace caf::detail { namespace caf {
class CAF_CORE_EXPORT uri_impl { /// Serializes an objects into a @ref config_value.
class CAF_CORE_EXPORT config_value_writer final : public serializer {
public: public:
// -- member types------------------------------------------------------------
using super = serializer;
struct present_field {
settings* parent;
string_view name;
string_view type;
};
struct absent_field {};
using value_type = variant<config_value*, settings*, absent_field,
present_field, std::vector<config_value>*>;
using stack_type = std::stack<value_type, std::vector<value_type>>;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
uri_impl(); config_value_writer(config_value* dst, actor_system& sys) : super(sys) {
st_.push(dst);
has_human_readable_format_ = true;
}
uri_impl(const uri_impl&) = delete; config_value_writer(config_value* dst, execution_unit* ctx) : super(ctx) {
st_.push(dst);
has_human_readable_format_ = true;
}
uri_impl& operator=(const uri_impl&) = delete; explicit config_value_writer(config_value* destination)
: config_value_writer(destination, nullptr) {
// nop
}
// -- member variables ------------------------------------------------------- ~config_value_writer() override;
static uri_impl default_instance; // -- interface functions ----------------------------------------------------
/// Null-terminated buffer for holding the string-representation of the URI. bool inject_next_object_type(type_id_t type) override;
std::string str;
/// Scheme component. bool begin_object(string_view name) override;
std::string scheme;
/// Assembled authority component. bool end_object() override;
uri::authority_type authority;
/// Path component. bool begin_field(string_view) override;
std::string path;
/// Query component as key-value pairs. bool begin_field(string_view name, bool is_present) override;
uri::query_map query;
/// The fragment component. bool begin_field(string_view name, span<const type_id_t> types,
std::string fragment; size_t index) override;
// -- properties ------------------------------------------------------------- bool begin_field(string_view name, bool is_present,
span<const type_id_t> types, size_t index) override;
bool valid() const noexcept { bool end_field() override;
return !scheme.empty() && (!authority.empty() || !path.empty());
}
// -- modifiers -------------------------------------------------------------- bool begin_tuple(size_t size) override;
/// Assembles the human-readable string representation for this URI. bool end_tuple() override;
void assemble_str();
// -- friend functions ------------------------------------------------------- bool begin_key_value_pair() override;
friend CAF_CORE_EXPORT void intrusive_ptr_add_ref(const uri_impl* p); bool end_key_value_pair() override;
friend CAF_CORE_EXPORT void intrusive_ptr_release(const uri_impl* p); bool begin_sequence(size_t size) override;
private: bool end_sequence() override;
// -- member variables -------------------------------------------------------
mutable std::atomic<size_t> rc_; bool begin_associative_array(size_t size) override;
};
// -- related free functions ------------------------------------------------- bool end_associative_array() override;
/// @relates uri_impl bool value(bool x) override;
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, uri_impl& x) { bool value(int8_t x) override;
auto load = [&] {
x.str.clear(); bool value(uint8_t x) override;
if (x.valid())
x.assemble_str(); bool value(int16_t x) override;
};
return f(x.scheme, x.authority, x.path, x.query, x.fragment, bool value(uint16_t x) override;
meta::load_callback(load));
} bool value(int32_t x) override;
bool value(uint32_t x) override;
bool value(int64_t x) override;
bool value(uint64_t x) override;
bool value(float x) override;
bool value(double x) override;
bool value(long double x) override;
bool value(string_view x) override;
bool value(const std::u16string& x) override;
bool value(const std::u32string& x) override;
bool value(span<const byte> x) override;
private:
bool push(config_value&& x);
stack_type st_;
string_view type_hint_;
};
} // namespace caf::detail } // namespace caf
...@@ -82,4 +82,11 @@ auto make_const_typed_message_view(const message& msg) { ...@@ -82,4 +82,11 @@ auto make_const_typed_message_view(const message& msg) {
return const_typed_message_view<Ts...>{}; return const_typed_message_view<Ts...>{};
} }
template <class... Ts>
optional<std::tuple<Ts...>> to_tuple(const message& msg) {
if (auto view = make_const_typed_message_view<Ts...>(msg))
return to_tuple(view);
return none;
}
} // namespace caf } // namespace caf
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <tuple> #include <tuple>
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
#include "caf/inspector_access.hpp"
#include "caf/make_copy_on_write.hpp" #include "caf/make_copy_on_write.hpp"
#include "caf/ref_counted.hpp" #include "caf/ref_counted.hpp"
...@@ -114,22 +115,6 @@ private: ...@@ -114,22 +115,6 @@ private:
intrusive_cow_ptr<impl> ptr_; intrusive_cow_ptr<impl> ptr_;
}; };
/// @relates cow_tuple
template <class Inspector, class... Ts>
typename std::enable_if<Inspector::reads_state,
typename Inspector::result_type>::type
inspect(Inspector& f, const cow_tuple<Ts...>& x) {
return f(x.data());
}
/// @relates cow_tuple
template <class Inspector, class... Ts>
typename std::enable_if<Inspector::writes_state,
typename Inspector::result_type>::type
inspect(Inspector& f, cow_tuple<Ts...>& x) {
return f(x.unshared());
}
/// Creates a new copy-on-write tuple from given arguments. /// Creates a new copy-on-write tuple from given arguments.
/// @relates cow_tuple /// @relates cow_tuple
template <class... Ts> template <class... Ts>
...@@ -144,4 +129,64 @@ auto get(const cow_tuple<Ts...>& xs) -> decltype(std::get<N>(xs.data())) { ...@@ -144,4 +129,64 @@ auto get(const cow_tuple<Ts...>& xs) -> decltype(std::get<N>(xs.data())) {
return std::get<N>(xs.data()); return std::get<N>(xs.data());
} }
// -- inspection ---------------------------------------------------------------
template <class... Ts>
struct inspector_access<cow_tuple<Ts...>> {
using value_type = cow_tuple<Ts...>;
template <class Inspector>
static bool apply_object(Inspector& f, value_type& x) {
if constexpr (Inspector::is_loading)
return detail::load_object(f, x.unshared());
else
return detail::save_object(f, detail::as_mutable_ref(x.data()));
}
template <class Inspector>
static bool apply_value(Inspector& f, value_type& x) {
if constexpr (Inspector::is_loading)
return detail::load_value(f, x.unshared());
else
return detail::save_value(f, detail::as_mutable_ref(x.data()));
}
template <class Inspector>
static bool save_field(Inspector& f, string_view field_name, value_type& x) {
return detail::save_field(f, field_name, detail::as_mutable_ref(x.data()));
}
template <class Inspector, class IsPresent, class Get>
static bool save_field(Inspector& f, string_view field_name,
IsPresent& is_present, Get& get) {
if constexpr (std::is_lvalue_reference<decltype(get())>::value) {
auto get_data = [&get]() -> decltype(auto) {
return detail::as_mutable_ref(get().data());
};
return detail::save_field(f, field_name, is_present, get_data);
} else {
auto get_data = [&get] {
auto tmp = get();
return std::move(tmp.unshared());
};
return detail::save_field(f, field_name, is_present, get_data);
}
}
template <class Inspector, class IsValid, class SyncValue>
static bool load_field(Inspector& f, string_view field_name, value_type& x,
IsValid& is_valid, SyncValue& sync_value) {
return detail::load_field(f, field_name, x.unshared(), is_valid,
sync_value);
}
template <class Inspector, class IsValid, class SyncValue, class SetFallback>
static bool load_field(Inspector& f, string_view field_name, value_type& x,
IsValid& is_valid, SyncValue& sync_value,
SetFallback& set_fallback) {
return detail::load_field(f, field_name, x.unshared(), is_valid, sync_value,
set_fallback);
}
};
} // namespace caf } // namespace caf
...@@ -30,32 +30,27 @@ namespace caf { ...@@ -30,32 +30,27 @@ namespace caf {
/// `to_string` for user-defined types via argument-dependent /// `to_string` for user-defined types via argument-dependent
/// loopkup (ADL). Any user-defined type that does not /// loopkup (ADL). Any user-defined type that does not
/// provide a `to_string` is mapped to `<unprintable>`. /// provide a `to_string` is mapped to `<unprintable>`.
template <class... Ts> template <class T>
std::string deep_to_string(const Ts&... xs) { std::string deep_to_string(const T& x) {
using inspector_type = detail::stringification_inspector;
std::string result; std::string result;
detail::stringification_inspector f{result}; inspector_type f{result};
f(xs...); detail::save_value(f, detail::as_mutable_ref(x));
return result; return result;
} }
/// Wrapper to `deep_to_string` for using the function as an inspector.
struct deep_to_string_t {
using result_type = std::string;
static constexpr bool reads_state = true;
static constexpr bool writes_state = false;
template <class... Ts>
result_type operator()(const Ts&... xs) const {
return deep_to_string(xs...);
}
};
/// Convenience function for `deep_to_string(std::forward_as_tuple(xs...))`. /// Convenience function for `deep_to_string(std::forward_as_tuple(xs...))`.
template <class... Ts> template <class... Ts>
std::string deep_to_string_as_tuple(const Ts&... xs) { std::string deep_to_string_as_tuple(const Ts&... xs) {
return deep_to_string(std::forward_as_tuple(xs...)); return deep_to_string(std::forward_as_tuple(xs...));
} }
/// Wraps `deep_to_string` into a function object.
struct deep_to_string_t {
template <class... Ts>
std::string operator()(const Ts&... xs) const {
return deep_to_string(xs...);
}
};
} // namespace caf } // namespace caf
...@@ -27,19 +27,16 @@ ...@@ -27,19 +27,16 @@
#include "caf/byte.hpp" #include "caf/byte.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/load_inspector_base.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
#include "caf/write_inspector.hpp" #include "caf/type_id.hpp"
namespace caf { namespace caf {
/// @ingroup TypeSystem /// @ingroup TypeSystem
/// Technology-independent deserialization interface. /// Technology-independent deserialization interface.
class CAF_CORE_EXPORT deserializer : public write_inspector<deserializer> { class CAF_CORE_EXPORT deserializer : public load_inspector_base<deserializer> {
public: public:
// -- member types -----------------------------------------------------------
using result_type = error;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
explicit deserializer(actor_system& sys) noexcept; explicit deserializer(actor_system& sys) noexcept;
...@@ -54,86 +51,129 @@ public: ...@@ -54,86 +51,129 @@ public:
return context_; return context_;
} }
bool has_human_readable_format() const noexcept {
return has_human_readable_format_;
}
// -- interface functions ---------------------------------------------------- // -- interface functions ----------------------------------------------------
/// Reads run-time-type information for the next object. Requires that the
/// @ref serializer provided this information via
/// @ref serializer::inject_next_object_type.
virtual bool fetch_next_object_type(type_id_t& type) = 0;
/// Begins processing of an object. /// Begins processing of an object.
virtual result_type begin_object(type_id_t& type) = 0; virtual bool begin_object(string_view type) = 0;
/// Ends processing of an object. /// Ends processing of an object.
virtual result_type end_object() = 0; virtual bool end_object() = 0;
virtual bool begin_field(string_view name) = 0;
virtual bool begin_field(string_view, bool& is_present) = 0;
virtual bool
begin_field(string_view name, span<const type_id_t> types, size_t& index)
= 0;
virtual bool begin_field(string_view name, bool& is_present,
span<const type_id_t> types, size_t& index)
= 0;
virtual bool end_field() = 0;
/// Begins processing of a fixed-size sequence.
virtual bool begin_tuple(size_t size) = 0;
/// Ends processing of a sequence.
virtual bool end_tuple() = 0;
/// Begins processing of a tuple with two elements, whereas the first element
/// represents the key in an associative array.
/// @note the default implementation calls `begin_tuple(2)`.
virtual bool begin_key_value_pair();
/// Ends processing of a key-value pair after both values were written.
/// @note the default implementation calls `end_tuple()`.
virtual bool end_key_value_pair();
/// Begins processing of a sequence. /// Begins processing of a sequence.
virtual result_type begin_sequence(size_t& size) = 0; virtual bool begin_sequence(size_t& size) = 0;
/// Ends processing of a sequence. /// Ends processing of a sequence.
virtual result_type end_sequence() = 0; virtual bool end_sequence() = 0;
/// Begins processing of an associative array (map).
/// @note the default implementation calls `begin_sequence(size)`.
virtual bool begin_associative_array(size_t& size);
/// Ends processing of an associative array (map).
/// @note the default implementation calls `end_sequence()`.
virtual bool end_associative_array();
/// Reads primitive value from the input. /// Reads primitive value from the input.
/// @param x The primitive value. /// @param x The primitive value.
/// @returns A non-zero error code on failure, `sec::success` otherwise. /// @returns A non-zero error code on failure, `sec::success` otherwise.
virtual result_type apply(bool& x) = 0; virtual bool value(bool& x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int8_t&) = 0; virtual bool value(int8_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint8_t&) = 0; virtual bool value(uint8_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int16_t&) = 0; virtual bool value(int16_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint16_t&) = 0; virtual bool value(uint16_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int32_t&) = 0; virtual bool value(int32_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint32_t&) = 0; virtual bool value(uint32_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int64_t&) = 0; virtual bool value(int64_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint64_t&) = 0; virtual bool value(uint64_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(float&) = 0; virtual bool value(float&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(double&) = 0; virtual bool value(double&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(long double&) = 0; virtual bool value(long double&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(std::string&) = 0; virtual bool value(std::string&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(std::u16string&) = 0; virtual bool value(std::u16string&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(std::u32string&) = 0; virtual bool value(std::u32string&) = 0;
/// @copydoc apply
template <class Enum, class = std::enable_if_t<std::is_enum<Enum>::value>>
auto apply(Enum& x) {
return apply(reinterpret_cast<std::underlying_type_t<Enum>&>(x));
}
/// Reads a byte sequence from the input. /// Reads a byte sequence from the input.
/// @param x The byte sequence. /// @param x The byte sequence.
/// @returns A non-zero error code on failure, `sec::success` otherwise. /// @returns A non-zero error code on failure, `sec::success` otherwise.
virtual result_type apply(span<byte> x) = 0; virtual bool value(span<byte> x) = 0;
/// Adds each boolean in `xs` to the output. Derived classes can override this /// Adds each boolean in `xs` to the output. Derived classes can override this
/// member function to pack the booleans, for example to avoid using one byte /// member function to pack the booleans, for example to avoid using one byte
/// for each value in a binary output format. /// for each value in a binary output format.
virtual result_type apply(std::vector<bool>& xs) noexcept; virtual bool value(std::vector<bool>& xs);
protected: protected:
/// Provides access to the ::proxy_registry and to the ::actor_system. /// Provides access to the ::proxy_registry and to the ::actor_system.
execution_unit* context_; execution_unit* context_;
/// Configures whether client code should assume human-readable output.
bool has_human_readable_format_ = false;
}; };
} // namespace caf } // namespace caf
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework * * | |___ / ___ \| _| Framework *
* \____/_/ \_|_| * * \____/_/ \_|_| *
* * * *
* Copyright 2011-2019 Dominik Charousset * * Copyright 2011-2020 Dominik Charousset *
* * * *
* Distributed under the terms and conditions of the BSD 3-Clause License or * * 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 * * (at your option) under the terms and conditions of the Boost Software *
...@@ -18,54 +18,19 @@ ...@@ -18,54 +18,19 @@
#pragma once #pragma once
#include <cstddef> // This function performs a const_cast. Naturally, calling it is almost always a
#include <tuple> // very bad idea. With one notable exception: writing code for type inspection.
#include "caf/config_value.hpp"
#include "caf/config_value_adaptor_field.hpp"
#include "caf/config_value_field.hpp"
#include "caf/detail/config_value_field_base.hpp"
#include "caf/string_view.hpp"
namespace caf::detail { namespace caf::detail {
template <class T, size_t Pos> template <class T>
class config_value_adaptor_field_impl T& as_mutable_ref(T& x) {
: public config_value_field_base<T, return x;
typename std::tuple_element<Pos, T>::type> { }
public:
using object_type = T;
using value_type = typename std::tuple_element<Pos, T>::type;
using field_type = config_value_adaptor_field<value_type>;
using predicate_type = bool (*)(const value_type&);
using super = config_value_field_base<object_type, value_type>;
explicit config_value_adaptor_field_impl(field_type x)
: super(x.name, std::move(x.default_value), x.predicate) {
// nop
}
config_value_adaptor_field_impl(config_value_adaptor_field_impl&&) = default;
const value_type& get_value(const object_type& x) const override {
return std::get<Pos>(x);
}
void set_value(object_type& x, value_type y) const override {
std::get<Pos>(x) = std::move(y);
}
};
template <class T, class Ps>
struct select_adaptor_fields;
template <class T, long... Pos> template <class T>
struct select_adaptor_fields<T, detail::int_list<Pos...>> { T& as_mutable_ref(const T& x) {
using type = std::tuple<config_value_adaptor_field_impl<T, Pos>...>; return const_cast<T&>(x);
}; }
} // namespace caf::detail } // namespace caf::detail
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include "caf/config_value.hpp"
#include "caf/config_value_field.hpp"
#include "caf/optional.hpp"
namespace caf::detail {
template <class Object, class Value>
class config_value_field_base : public config_value_field<Object> {
public:
using super = config_value_field<Object>;
using object_type = typename super::object_type;
using value_type = Value;
using predicate_type = bool (*)(const value_type&);
config_value_field_base(string_view name, optional<value_type> default_value,
predicate_type predicate)
: name_(name),
default_value_(std::move(default_value)),
predicate_(predicate) {
// nop
}
config_value_field_base(config_value_field_base&&) = default;
bool has_default() const noexcept override {
return static_cast<bool>(default_value_);
}
string_view name() const noexcept override {
return name_;
}
config_value get(const object_type& object) const override {
using access = caf::select_config_value_access_t<value_type>;
return config_value{access::convert(get_value(object))};
}
bool valid_input(const config_value& x) const override {
if (!predicate_)
return holds_alternative<value_type>(x);
if (auto value = get_if<value_type>(&x))
return predicate_(*value);
return false;
}
bool set(object_type& x, const config_value& y) const override {
if (auto value = get_if<value_type>(&y)) {
if (predicate_ && !predicate_(*value))
return false;
set_value(x, move_if_optional(value));
return true;
}
return false;
}
void set_default(object_type& x) const override {
set_value(x, *default_value_);
}
void parse_cli(string_parser_state& ps, object_type& x,
bool nested) const override {
using access = caf::select_config_value_access_t<value_type>;
value_type tmp;
if (nested)
access::parse_cli(ps, tmp, nested_cli_parsing);
else
access::parse_cli(ps, tmp, top_level_cli_parsing);
if (ps.code <= pec::trailing_character) {
if (predicate_ && !predicate_(tmp))
ps.code = pec::invalid_argument;
else
set_value(x, std::move(tmp));
}
}
virtual const value_type& get_value(const object_type& object) const = 0;
virtual void set_value(object_type& object, value_type value) const = 0;
protected:
string_view name_;
optional<value_type> default_value_;
predicate_type predicate_;
};
} // namespace caf::detail
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include <string>
#include <utility>
#include "caf/config_value.hpp"
#include "caf/config_value_field.hpp"
#include "caf/detail/config_value_field_base.hpp"
#include "caf/detail/parse.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/optional.hpp"
#include "caf/string_view.hpp"
namespace caf::detail {
template <class MemberObjectPointer>
class config_value_field_impl;
// A config value with direct access to a field via member object pointer.
template <class Value, class Object>
class config_value_field_impl<Value Object::*>
: public config_value_field_base<Object, Value> {
public:
using super = config_value_field_base<Object, Value>;
using member_pointer = Value Object::*;
using object_type = Object;
using value_type = Value;
using predicate_type = bool (*)(const value_type&);
constexpr config_value_field_impl(string_view name, member_pointer ptr,
optional<value_type> default_value = none,
predicate_type predicate = nullptr)
: super(name, std::move(default_value), predicate), ptr_(ptr) {
// nop
}
constexpr config_value_field_impl(config_value_field_impl&&) = default;
const value_type& get_value(const object_type& x) const override {
return x.*ptr_;
}
void set_value(object_type& x, value_type y) const override {
x.*ptr_ = std::move(y);
}
private:
member_pointer ptr_;
};
template <class Get>
struct config_value_field_trait {
using trait = get_callable_trait_t<Get>;
static_assert(trait::num_args == 1,
"Get must take exactly one argument (the object)");
using get_argument_type = tl_head_t<typename trait::arg_types>;
using object_type = decay_t<get_argument_type>;
using get_result_type = typename trait::result_type;
using value_type = decay_t<get_result_type>;
};
// A config value with access to a field via getter and setter.
template <class Get, class Set>
class config_value_field_impl<std::pair<Get, Set>>
: public config_value_field_base<
typename config_value_field_trait<Get>::object_type,
typename config_value_field_trait<Get>::value_type> {
public:
using trait = config_value_field_trait<Get>;
using object_type = typename trait::object_type;
using get_result_type = typename trait::get_result_type;
using value_type = typename trait::value_type;
using predicate_type = bool (*)(const value_type&);
using super = config_value_field_base<object_type, value_type>;
constexpr config_value_field_impl(string_view name, Get getter, Set setter,
optional<value_type> default_value = none,
predicate_type predicate = nullptr)
: super(name, std::move(default_value), predicate),
get_(std::move(getter)),
set_(std::move(setter)) {
// nop
}
constexpr config_value_field_impl(config_value_field_impl&&) = default;
const value_type& get_value(const object_type& x) const override {
bool_token<std::is_lvalue_reference<get_result_type>::value> token;
return get_value_impl(x, token);
}
void set_value(object_type& x, value_type y) const override {
set_(x, std::move(y));
}
private:
template <class O>
const value_type& get_value_impl(const O& x, std::true_type) const {
return get_(x);
}
template <class O>
const value_type& get_value_impl(const O& x, std::false_type) const {
dummy_ = get_(x);
return dummy_;
}
Get get_;
Set set_;
mutable value_type dummy_;
};
} // namespace caf::detail
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "caf/detail/meta_object.hpp" #include "caf/detail/meta_object.hpp"
#include "caf/detail/padded_size.hpp" #include "caf/detail/padded_size.hpp"
#include "caf/detail/stringification_inspector.hpp" #include "caf/detail/stringification_inspector.hpp"
#include "caf/error.hpp" #include "caf/inspector_access.hpp"
#include "caf/serializer.hpp" #include "caf/serializer.hpp"
namespace caf::detail::default_function { namespace caf::detail::default_function {
...@@ -45,33 +45,34 @@ void default_construct(void* ptr) { ...@@ -45,33 +45,34 @@ void default_construct(void* ptr) {
template <class T> template <class T>
void copy_construct(void* ptr, const void* src) { void copy_construct(void* ptr, const void* src) {
new (ptr) T(*reinterpret_cast<const T*>(src)); new (ptr) T(*static_cast<const T*>(src));
} }
template <class T> template <class T>
error_code<sec> save_binary(caf::binary_serializer& sink, const void* ptr) { bool save_binary(binary_serializer& sink, const void* ptr) {
return sink(*reinterpret_cast<const T*>(ptr)); return sink.apply_object(*static_cast<const T*>(ptr));
} }
template <class T> template <class T>
error_code<sec> load_binary(caf::binary_deserializer& source, void* ptr) { bool load_binary(binary_deserializer& source, void* ptr) {
return source(*reinterpret_cast<T*>(ptr)); return source.apply_object(*static_cast<T*>(ptr));
} }
template <class T> template <class T>
caf::error save(caf::serializer& sink, const void* ptr) { bool save(serializer& sink, const void* ptr) {
return sink(*reinterpret_cast<const T*>(ptr)); return sink.apply_object(*static_cast<const T*>(ptr));
} }
template <class T> template <class T>
caf::error load(caf::deserializer& source, void* ptr) { bool load(deserializer& source, void* ptr) {
return source(*reinterpret_cast<T*>(ptr)); return source.apply_object(*static_cast<T*>(ptr));
} }
template <class T> template <class T>
void stringify(std::string& buf, const void* ptr) { void stringify(std::string& buf, const void* ptr) {
stringification_inspector f{buf}; stringification_inspector f{buf};
f(*reinterpret_cast<const T*>(ptr)); auto unused = f.apply_object(*static_cast<const T*>(ptr));
static_cast<void>(unused);
} }
} // namespace caf::detail::default_function } // namespace caf::detail::default_function
...@@ -79,7 +80,7 @@ void stringify(std::string& buf, const void* ptr) { ...@@ -79,7 +80,7 @@ void stringify(std::string& buf, const void* ptr) {
namespace caf::detail { namespace caf::detail {
template <class T> template <class T>
meta_object make_meta_object(const char* type_name) { meta_object make_meta_object(string_view type_name) {
return { return {
type_name, type_name,
padded_size_v<T>, padded_size_v<T>,
......
...@@ -54,7 +54,7 @@ public: ...@@ -54,7 +54,7 @@ public:
message_data& operator=(const message_data&) = delete; message_data& operator=(const message_data&) = delete;
/// Constructs the message data object *without* constructing any element. /// Constructs the message data object *without* constructing any element.
explicit message_data(type_id_list types); explicit message_data(type_id_list types) noexcept;
~message_data() noexcept; ~message_data() noexcept;
...@@ -115,17 +115,31 @@ public: ...@@ -115,17 +115,31 @@ public:
/// @copydoc at /// @copydoc at
const byte* at(size_t index) const noexcept; const byte* at(size_t index) const noexcept;
caf::error save(caf::serializer& sink) const; void inc_constructed_elements() {
++constructed_elements_;
}
caf::error save(caf::binary_serializer& sink) const; template <class... Ts>
void init(Ts&&... xs) {
init_impl(storage(), std::forward<Ts>(xs)...);
}
caf::error load(caf::deserializer& source); private:
void init_impl(byte*) {
// nop
}
caf::error load(caf::binary_deserializer& source); template <class T, class... Ts>
void init_impl(byte* storage, T&& x, Ts&&... xs) {
using type = strip_and_convert_t<T>;
new (storage) type(std::forward<T>(x));
++constructed_elements_;
init_impl(storage + padded_size_v<type>, std::forward<Ts>(xs)...);
}
private:
mutable std::atomic<size_t> rc_; mutable std::atomic<size_t> rc_;
type_id_list types_; type_id_list types_;
size_t constructed_elements_;
byte storage_[]; byte storage_[];
}; };
...@@ -141,19 +155,6 @@ inline void intrusive_ptr_release(message_data* ptr) { ...@@ -141,19 +155,6 @@ inline void intrusive_ptr_release(message_data* ptr) {
ptr->deref(); ptr->deref();
} }
inline void message_data_init(byte*) {
// nop
}
template <class T, class... Ts>
void message_data_init(byte* storage, T&& x, Ts&&... xs) {
// TODO: exception safety: if any constructor throws, we need to unwind the
// stack here and call destructors.
using type = strip_and_convert_t<T>;
new (storage) type(std::forward<T>(x));
message_data_init(storage + padded_size_v<type>, std::forward<Ts>(xs)...);
}
} // namespace caf::detail } // namespace caf::detail
#ifdef CAF_CLANG #ifdef CAF_CLANG
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
#include "caf/string_view.hpp"
namespace caf::detail { namespace caf::detail {
...@@ -31,7 +32,7 @@ namespace caf::detail { ...@@ -31,7 +32,7 @@ namespace caf::detail {
/// pointers. /// pointers.
struct meta_object { struct meta_object {
/// Stores a human-readable representation of the type's name. /// Stores a human-readable representation of the type's name.
const char* type_name = nullptr; string_view type_name;
/// Stores how many Bytes objects of this type require, including padding for /// Stores how many Bytes objects of this type require, including padding for
/// aligning to `max_align_t`. /// aligning to `max_align_t`.
...@@ -49,37 +50,21 @@ struct meta_object { ...@@ -49,37 +50,21 @@ struct meta_object {
void (*copy_construct)(void*, const void*); void (*copy_construct)(void*, const void*);
/// Applies an object to a binary serializer. /// Applies an object to a binary serializer.
error_code<sec> (*save_binary)(caf::binary_serializer&, const void*); bool (*save_binary)(caf::binary_serializer&, const void*);
/// Applies an object to a binary deserializer. /// Applies an object to a binary deserializer.
error_code<sec> (*load_binary)(caf::binary_deserializer&, void*); bool (*load_binary)(caf::binary_deserializer&, void*);
/// Applies an object to a generic serializer. /// Applies an object to a generic serializer.
caf::error (*save)(caf::serializer&, const void*); bool (*save)(caf::serializer&, const void*);
/// Applies an object to a generic deserializer. /// Applies an object to a generic deserializer.
caf::error (*load)(caf::deserializer&, void*); bool (*load)(caf::deserializer&, void*);
/// Appends a string representation of an object to a buffer. /// Appends a string representation of an object to a buffer.
void (*stringify)(std::string&, const void*); void (*stringify)(std::string&, const void*);
}; };
/// Convenience function for calling `meta.save(sink, obj)`.
CAF_CORE_EXPORT caf::error save(const meta_object& meta, caf::serializer& sink,
const void* obj);
/// Convenience function for calling `meta.save_binary(sink, obj)`.
CAF_CORE_EXPORT caf::error_code<sec>
save(const meta_object& meta, caf::binary_serializer& sink, const void* obj);
/// Convenience function for calling `meta.load(source, obj)`.
CAF_CORE_EXPORT caf::error load(const meta_object& meta,
caf::deserializer& source, void* obj);
/// Convenience function for calling `meta.load_binary(source, obj)`.
CAF_CORE_EXPORT caf::error_code<sec>
load(const meta_object& meta, caf::binary_deserializer& source, void* obj);
/// Returns the global storage for all meta objects. The ::type_id of an object /// Returns the global storage for all meta objects. The ::type_id of an object
/// is the index for accessing the corresonding meta object. /// is the index for accessing the corresonding meta object.
CAF_CORE_EXPORT span<const meta_object> global_meta_objects(); CAF_CORE_EXPORT span<const meta_object> global_meta_objects();
......
...@@ -38,6 +38,26 @@ ...@@ -38,6 +38,26 @@
namespace caf::detail { namespace caf::detail {
// -- utility types ------------------------------------------------------------
enum class time_unit {
invalid,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds,
};
CAF_CORE_EXPORT void parse(string_parser_state& ps, time_unit& x);
struct literal {
string_view str;
};
CAF_CORE_EXPORT void parse(string_parser_state& ps, literal x);
// -- boolean type ------------------------------------------------------------- // -- boolean type -------------------------------------------------------------
CAF_CORE_EXPORT void parse(string_parser_state& ps, bool& x); CAF_CORE_EXPORT void parse(string_parser_state& ps, bool& x);
...@@ -77,9 +97,9 @@ CAF_CORE_EXPORT void parse(string_parser_state& ps, float& x); ...@@ -77,9 +97,9 @@ CAF_CORE_EXPORT void parse(string_parser_state& ps, float& x);
CAF_CORE_EXPORT void parse(string_parser_state& ps, double& x); CAF_CORE_EXPORT void parse(string_parser_state& ps, double& x);
// -- CAF types ---------------------------------------------------------------- CAF_CORE_EXPORT void parse(string_parser_state& ps, long double& x);
CAF_CORE_EXPORT void parse(string_parser_state& ps, timespan& x); // -- CAF types ----------------------------------------------------------------
CAF_CORE_EXPORT void parse(string_parser_state& ps, ipv4_address& x); CAF_CORE_EXPORT void parse(string_parser_state& ps, ipv4_address& x);
...@@ -95,10 +115,100 @@ CAF_CORE_EXPORT void parse(string_parser_state& ps, ipv6_endpoint& x); ...@@ -95,10 +115,100 @@ CAF_CORE_EXPORT void parse(string_parser_state& ps, ipv6_endpoint& x);
CAF_CORE_EXPORT void parse(string_parser_state& ps, uri& x); CAF_CORE_EXPORT void parse(string_parser_state& ps, uri& x);
CAF_CORE_EXPORT void parse(string_parser_state& ps, config_value& x);
// -- variadic utility ---------------------------------------------------------
template <class... Ts>
bool parse_sequence(string_parser_state& ps, Ts&&... xs) {
auto parse_one = [&](auto& x) {
parse(ps, x);
return ps.code <= pec::trailing_character;
};
return (parse_one(xs) && ...);
}
// -- STL types ---------------------------------------------------------------- // -- STL types ----------------------------------------------------------------
CAF_CORE_EXPORT void parse(string_parser_state& ps, std::string& x); CAF_CORE_EXPORT void parse(string_parser_state& ps, std::string& x);
template <class Rep, class Period>
void parse(string_parser_state& ps, std::chrono::duration<Rep, Period>& x) {
namespace sc = std::chrono;
using value_type = sc::duration<Rep, Period>;
auto set = [&x](auto value) { x = sc::duration_cast<value_type>(value); };
auto count = 0.0;
auto suffix = time_unit::invalid;
parse_sequence(ps, count, suffix);
if (ps.code == pec::success) {
switch (suffix) {
case time_unit::hours:
set(sc::duration<double, std::ratio<3600>>{count});
break;
case time_unit::minutes:
set(sc::duration<double, std::ratio<60>>{count});
break;
case time_unit::seconds:
set(sc::duration<double>{count});
break;
case time_unit::milliseconds:
set(sc::duration<double, std::milli>{count});
break;
case time_unit::microseconds:
set(sc::duration<double, std::micro>{count});
break;
case time_unit::nanoseconds:
set(sc::duration<double, std::nano>{count});
break;
default:
ps.code = pec::invalid_state;
}
}
}
template <class Duration>
void parse(string_parser_state& ps,
std::chrono::time_point<std::chrono::system_clock, Duration>& x) {
namespace sc = std::chrono;
using value_type = sc::time_point<sc::system_clock, Duration>;
// Parse ISO 8601 as generated by detail::print.
int32_t year = 0;
int32_t month = 0;
int32_t day = 0;
int32_t hour = 0;
int32_t minute = 0;
int32_t second = 0;
int32_t milliseconds = 0;
if (!parse_sequence(ps,
// YYYY-MM-DD
year, literal{{"-"}}, month, literal{{"-"}}, day,
// "T"
literal{{"T"}},
// hh:mm:ss
hour, literal{{":"}}, minute, literal{{":"}}, second,
// "." xxx
literal{{"."}}, milliseconds))
return;
if (ps.code != pec::success)
return;
// Fill tm record.
tm record;
record.tm_sec = second;
record.tm_min = minute;
record.tm_hour = hour;
record.tm_mday = day;
record.tm_mon = month - 1; // months since January
record.tm_year = year - 1900; // years since 1900
record.tm_wday = -1; // n/a
record.tm_yday = -1; // n/a
record.tm_isdst = -1; // n/a
// Convert to chrono time and add the milliseconds.
auto tstamp = sc::system_clock::from_time_t(mktime(&record));
auto since_epoch = sc::duration_cast<Duration>(tstamp.time_since_epoch());
since_epoch += sc::milliseconds{milliseconds};
x = value_type{since_epoch};
}
// -- container types ---------------------------------------------------------- // -- container types ----------------------------------------------------------
CAF_CORE_EXPORT void parse_element(string_parser_state& ps, std::string& x, CAF_CORE_EXPORT void parse_element(string_parser_state& ps, std::string& x,
...@@ -186,13 +296,14 @@ void parse_element(string_parser_state& ps, std::pair<First, Second>& kvp, ...@@ -186,13 +296,14 @@ void parse_element(string_parser_state& ps, std::pair<First, Second>& kvp,
// -- convenience functions ---------------------------------------------------- // -- convenience functions ----------------------------------------------------
CAF_CORE_EXPORT
error parse_result(const string_parser_state& ps, string_view input);
template <class T> template <class T>
error parse(string_view str, T& x) { auto parse(string_view str, T& x) {
string_parser_state ps{str.begin(), str.end()}; string_parser_state ps{str.begin(), str.end()};
parse(ps, x); parse(ps, x);
if (ps.code == pec::success) return parse_result(ps, str);
return none;
return make_error(ps.code, std::string{str.begin(), str.end()});
} }
} // namespace caf::detail } // namespace caf::detail
...@@ -119,7 +119,6 @@ void read_config_map(State& ps, Consumer&& consumer) { ...@@ -119,7 +119,6 @@ void read_config_map(State& ps, Consumer&& consumer) {
fsm_epsilon(read_string(ps, key), await_assignment, quote_marks) fsm_epsilon(read_string(ps, key), await_assignment, quote_marks)
transition(read_key_name, alnum_or_dash, key = ch) transition(read_key_name, alnum_or_dash, key = ch)
transition_if(Nested, done, '}', consumer.end_map()) transition_if(Nested, done, '}', consumer.end_map())
epsilon_if(!Nested, done)
} }
// Reads a key of a "key=value" line. // Reads a key of a "key=value" line.
state(read_key_name) { state(read_key_name) {
...@@ -219,6 +218,9 @@ void read_config_value(State& ps, Consumer&& consumer, InsideList inside_list) { ...@@ -219,6 +218,9 @@ void read_config_value(State& ps, Consumer&& consumer, InsideList inside_list) {
template <class State, class Consumer> template <class State, class Consumer>
void read_config(State& ps, Consumer&& consumer) { void read_config(State& ps, Consumer&& consumer) {
auto key_char = [](char x) {
return isalnum(x) || x == '-' || x == '_' || x == '"';
};
// clang-format off // clang-format off
start(); start();
// Checks whether there's a top-level '{'. // Checks whether there's a top-level '{'.
...@@ -226,12 +228,12 @@ void read_config(State& ps, Consumer&& consumer) { ...@@ -226,12 +228,12 @@ void read_config(State& ps, Consumer&& consumer) {
transition(init, " \t\n") transition(init, " \t\n")
fsm_epsilon(read_config_comment(ps, consumer), init, '#') fsm_epsilon(read_config_comment(ps, consumer), init, '#')
fsm_transition(read_config_map<false>(ps, consumer), fsm_transition(read_config_map<false>(ps, consumer),
await_closing_brance, '{') await_closing_brace, '{')
fsm_epsilon(read_config_map<false>(ps, consumer), init) fsm_epsilon(read_config_map<false>(ps, consumer), init, key_char)
} }
state(await_closing_brance) { state(await_closing_brace) {
transition(await_closing_brance, " \t\n") transition(await_closing_brace, " \t\n")
fsm_epsilon(read_config_comment(ps, consumer), await_closing_brance, '#') fsm_epsilon(read_config_comment(ps, consumer), await_closing_brace, '#')
transition(done, '}') transition(done, '}')
} }
term_state(done) { term_state(done) {
......
...@@ -125,7 +125,7 @@ void read_floating_point(State& ps, Consumer&& consumer, ...@@ -125,7 +125,7 @@ void read_floating_point(State& ps, Consumer&& consumer,
state(has_sign) { state(has_sign) {
transition(leading_dot, '.') transition(leading_dot, '.')
transition(zero, '0') transition(zero, '0')
epsilon(dec) epsilon(dec, decimal_chars)
} }
term_state(zero) { term_state(zero) {
transition(trailing_dot, '.') transition(trailing_dot, '.')
...@@ -134,7 +134,7 @@ void read_floating_point(State& ps, Consumer&& consumer, ...@@ -134,7 +134,7 @@ void read_floating_point(State& ps, Consumer&& consumer,
term_state(dec) { term_state(dec) {
transition(dec, decimal_chars, add_ascii<10>(result, ch), transition(dec, decimal_chars, add_ascii<10>(result, ch),
pec::integer_overflow) pec::integer_overflow)
epsilon(after_dec) epsilon(after_dec, "eE.")
} }
state(after_dec) { state(after_dec) {
transition(has_e, "eE") transition(has_e, "eE")
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include "caf/string_view.hpp"
#include <chrono>
#include <cstdint>
#include <ctime>
#include <limits>
#include <type_traits>
namespace caf::detail {
CAF_CORE_EXPORT
size_t print_timestamp(char* buf, size_t buf_size, time_t ts, size_t ms);
template <class Buffer>
void print_escaped(Buffer& buf, string_view str) {
buf.push_back('"');
for (auto c : str) {
switch (c) {
default:
buf.push_back(c);
break;
case '\n':
buf.push_back('\\');
buf.push_back('n');
break;
case '\t':
buf.push_back('\\');
buf.push_back('t');
break;
case '\\':
buf.push_back('\\');
buf.push_back('\\');
break;
case '"':
buf.push_back('\\');
buf.push_back('"');
break;
}
}
buf.push_back('"');
}
template <class Buffer>
void print(Buffer& buf, bool x) {
using namespace caf::literals;
auto str = x ? "true"_sv : "false"_sv;
buf.insert(buf.end(), str.begin(), str.end());
}
template <class Buffer, class T>
std::enable_if_t<std::is_integral<T>::value> print(Buffer& buf, T x) {
// An integer can at most have 20 digits (UINT64_MAX).
char stack_buffer[24];
char* p = stack_buffer;
// Convert negative values into positives as necessary.
if constexpr (std::is_signed<T>::value) {
if (x == std::numeric_limits<T>::min()) {
using namespace caf::literals;
// The code below would fail for the smallest value, because this value
// has no positive counterpart. For example, an int8_t ranges from -128 to
// 127. Hence, an int8_t cannot represent `abs(-128)`.
string_view result;
if constexpr (sizeof(T) == 1) {
result = "-128"_sv;
} else if constexpr (sizeof(T) == 2) {
result = "-32768"_sv;
} else if constexpr (sizeof(T) == 4) {
result = "-2147483648"_sv;
} else {
static_assert(sizeof(T) == 8);
result = "-9223372036854775808"_sv;
}
buf.insert(buf.end(), result.begin(), result.end());
return;
}
if (x < 0) {
buf.push_back('-');
x = -x;
}
}
// Fill the buffer.
*p++ = static_cast<char>((x % 10) + '0');
x /= 10;
while (x != 0) {
*p++ = static_cast<char>((x % 10) + '0');
x /= 10;
}
// Now, the buffer holds the string representation in reverse order.
do {
buf.push_back(*--p);
} while (p != stack_buffer);
}
template <class Buffer, class T>
std::enable_if_t<std::is_floating_point<T>::value> print(Buffer& buf, T x) {
// TODO: Check whether to_chars is available on supported compilers and
// re-implement using the new API as soon as possible.
auto str = std::to_string(x);
if (str.find('.') != std::string::npos) {
// Drop trailing zeros.
while (str.back() == '0')
str.pop_back();
// Drop trailing dot as well if we've removed all decimal places.
if (str.back() == '.')
str.pop_back();
}
buf.insert(buf.end(), str.begin(), str.end());
}
template <class Buffer, class Rep, class Period>
void print(Buffer& buf, std::chrono::duration<Rep, Period> x) {
using namespace caf::literals;
if (x.count() == 0) {
auto str = "1s"_sv;
buf.insert(buf.end(), str.begin(), str.end());
return;
}
auto try_print = [&buf](auto converted, string_view suffix) {
if (converted.count() < 1)
return false;
print(buf, converted.count());
buf.insert(buf.end(), suffix.begin(), suffix.end());
return true;
};
namespace sc = std::chrono;
using hours = sc::duration<double, std::ratio<3600>>;
using minutes = sc::duration<double, std::ratio<60>>;
using seconds = sc::duration<double>;
using milliseconds = sc::duration<double, std::milli>;
using microseconds = sc::duration<double, std::micro>;
if (try_print(sc::duration_cast<hours>(x), "h")
|| try_print(sc::duration_cast<minutes>(x), "min")
|| try_print(sc::duration_cast<seconds>(x), "s")
|| try_print(sc::duration_cast<milliseconds>(x), "ms")
|| try_print(sc::duration_cast<microseconds>(x), "us"))
return;
auto converted = sc::duration_cast<sc::nanoseconds>(x);
print(buf, converted.count());
auto suffix = "ns"_sv;
buf.insert(buf.end(), suffix.begin(), suffix.end());
}
template <class Buffer, class Duration>
void print(Buffer& buf,
std::chrono::time_point<std::chrono::system_clock, Duration> x) {
namespace sc = std::chrono;
using clock_type = sc::system_clock;
using clock_timestamp = typename clock_type::time_point;
using clock_duration = typename clock_type::duration;
auto tse = x.time_since_epoch();
clock_timestamp as_sys_time{sc::duration_cast<clock_duration>(tse)};
auto secs = clock_type::to_time_t(as_sys_time);
auto msecs = sc::duration_cast<sc::milliseconds>(tse).count() % 1000;
// We print in ISO 8601 format, e.g., "2020-09-01T15:58:42.372". 32-Bytes are
// more than enough space.
char stack_buffer[32];
auto pos = print_timestamp(stack_buffer, 32, secs, msecs);
buf.insert(buf.end(), stack_buffer, stack_buffer + pos);
}
} // namespace caf::detail
...@@ -32,62 +32,80 @@ public: ...@@ -32,62 +32,80 @@ public:
size_t result = 0; size_t result = 0;
result_type begin_object(type_id_t) override; bool inject_next_object_type(type_id_t type) override;
result_type end_object() override; bool begin_object(string_view) override;
result_type begin_sequence(size_t num) override; bool end_object() override;
result_type end_sequence() override; bool begin_field(string_view) override;
result_type apply(bool x) override; bool begin_field(string_view, bool is_present) override;
result_type apply(int8_t x) override; bool begin_field(string_view, span<const type_id_t> types,
size_t index) override;
result_type apply(uint8_t x) override; bool begin_field(string_view, bool is_present, span<const type_id_t> types,
size_t index) override;
result_type apply(int16_t x) override; bool end_field() override;
result_type apply(uint16_t x) override; bool begin_tuple(size_t size) override;
result_type apply(int32_t x) override; bool end_tuple() override;
result_type apply(uint32_t x) override; bool begin_sequence(size_t size) override;
result_type apply(int64_t x) override; bool end_sequence() override;
result_type apply(uint64_t x) override; bool value(bool x) override;
result_type apply(float x) override; bool value(int8_t x) override;
result_type apply(double x) override; bool value(uint8_t x) override;
result_type apply(long double x) override; bool value(int16_t x) override;
result_type apply(string_view x) override; bool value(uint16_t x) override;
result_type apply(const std::u16string& x) override; bool value(int32_t x) override;
result_type apply(const std::u32string& x) override; bool value(uint32_t x) override;
result_type apply(span<const byte> x) override; bool value(int64_t x) override;
result_type apply(const std::vector<bool>& xs) override; bool value(uint64_t x) override;
bool value(float x) override;
bool value(double x) override;
bool value(long double x) override;
bool value(string_view x) override;
bool value(const std::u16string& x) override;
bool value(const std::u32string& x) override;
bool value(span<const byte> x) override;
bool value(const std::vector<bool>& xs) override;
}; };
template <class T> template <class T>
size_t serialized_size(actor_system& sys, const T& x) { size_t serialized_size(const T& x) {
serialized_size_inspector f{sys}; serialized_size_inspector f;
auto err = f(x); auto unused = f.apply_object(x);
static_cast<void>(err); static_cast<void>(unused); // Always true.
return f.result; return f.result;
} }
template <class T> template <class T>
size_t serialized_size(const T& x) { size_t serialized_size(actor_system& sys, const T& x) {
serialized_size_inspector f{nullptr}; serialized_size_inspector f{sys};
auto err = f(x); auto unused = f.apply_object(x);
static_cast<void>(err); static_cast<void>(unused); // Always true.
return f.result; return f.result;
} }
......
...@@ -65,10 +65,8 @@ public: ...@@ -65,10 +65,8 @@ public:
this->sample_counter_ = 0; this->sample_counter_ = 0;
this->inspector_.result = 0; this->inspector_.result = 0;
this->sampled_elements_ += x.xs_size; this->sampled_elements_ += x.xs_size;
for (auto& element : x.xs.get_as<std::vector<T>>(0)) { for (auto& element : x.xs.get_as<std::vector<T>>(0))
auto res = this->inspector_(element); detail::save_value(this->inspector_, element);
static_cast<void>(res); // This inspector never produces an error.
}
this->sampled_total_size_ this->sampled_total_size_
+= static_cast<int64_t>(this->inspector_.result); += static_cast<int64_t>(this->inspector_.result);
} }
......
...@@ -28,33 +28,53 @@ namespace caf::detail { ...@@ -28,33 +28,53 @@ namespace caf::detail {
class CAF_CORE_EXPORT type_id_list_builder { class CAF_CORE_EXPORT type_id_list_builder {
public: public:
// -- constants --------------------------------------------------------------
static constexpr size_t block_size = 8; static constexpr size_t block_size = 8;
// -- constructors, destructors, and assignment operators --------------------
type_id_list_builder(); type_id_list_builder();
~type_id_list_builder(); ~type_id_list_builder();
// -- modifiers
// ---------------------------------------------------------------
void reserve(size_t new_capacity); void reserve(size_t new_capacity);
void push_back(type_id_t id); void push_back(type_id_t id);
/// Returns the number of elements currenty stored in the array. void clear() noexcept {
if (storage_)
size_ = 1;
}
// -- properties -------------------------------------------------------------
size_t size() const noexcept; size_t size() const noexcept;
/// @pre `index < size()` /// @pre `index < size()`
type_id_t operator[](size_t index) const noexcept; type_id_t operator[](size_t index) const noexcept;
/// Convertes the internal buffer to a ::type_id_list and returns it. // -- iterator access --------------------------------------------------------
type_id_list move_to_list() noexcept;
/// Convertes the internal buffer to a ::type_id_list and returns it. auto begin() const noexcept {
type_id_list copy_to_list() const; return storage_;
}
void clear() noexcept { auto end() const noexcept {
if (storage_) return storage_ + size_;
size_ = 1;
} }
// -- conversions ------------------------------------------------------------
/// Convertes the internal buffer to a @ref type_id_list and returns it.
type_id_list move_to_list() noexcept;
/// Convertes the internal buffer to a @ref type_id_list and returns it.
type_id_list copy_to_list() const;
private: private:
size_t size_; size_t size_;
size_t reserved_; size_t reserved_;
......
...@@ -67,6 +67,9 @@ ...@@ -67,6 +67,9 @@
namespace caf::detail { namespace caf::detail {
template <class T>
constexpr T* null_v = nullptr;
// -- backport of C++14 additions ---------------------------------------------- // -- backport of C++14 additions ----------------------------------------------
template <class T> template <class T>
...@@ -651,12 +654,44 @@ struct is_map_like { ...@@ -651,12 +654,44 @@ struct is_map_like {
template <class T> template <class T>
constexpr bool is_map_like_v = is_map_like<T>::value; constexpr bool is_map_like_v = is_map_like<T>::value;
template <class T>
struct has_insert {
private:
template <class List>
static auto sfinae(List* l, typename List::value_type* x = nullptr)
-> decltype(l->insert(l->end(), *x), std::true_type());
template <class U>
static auto sfinae(...) -> std::false_type;
using sfinae_type = decltype(sfinae<T>(nullptr));
public:
static constexpr bool value = sfinae_type::value;
};
template <class T>
struct has_size {
private:
template <class List>
static auto sfinae(List* l) -> decltype(l->size(), std::true_type());
template <class U>
static auto sfinae(...) -> std::false_type;
using sfinae_type = decltype(sfinae<T>(nullptr));
public:
static constexpr bool value = sfinae_type::value;
};
/// Checks whether T behaves like `std::vector`, `std::list`, or `std::set`. /// Checks whether T behaves like `std::vector`, `std::list`, or `std::set`.
template <class T> template <class T>
struct is_list_like { struct is_list_like {
static constexpr bool value = is_iterable<T>::value static constexpr bool value = is_iterable<T>::value
&& has_value_type_alias<T>::value && has_value_type_alias<T>::value
&& !has_mapped_type_alias<T>::value; && !has_mapped_type_alias<T>::value
&& has_insert<T>::value && has_size<T>::value;
}; };
template <class T> template <class T>
...@@ -747,6 +782,140 @@ struct is_stl_tuple_type { ...@@ -747,6 +782,140 @@ struct is_stl_tuple_type {
template <class T> template <class T>
constexpr bool is_stl_tuple_type_v = is_stl_tuple_type<T>::value; constexpr bool is_stl_tuple_type_v = is_stl_tuple_type<T>::value;
template <class Inspector>
class has_context {
private:
template <class F>
static auto sfinae(F& f) -> decltype(f.context());
static void sfinae(...);
using result_type = decltype(sfinae(std::declval<Inspector&>()));
public:
static constexpr bool value
= std::is_same<result_type, execution_unit*>::value;
};
/// Checks whether `T` provides an `inspect` overload for `Inspector`.
template <class Inspector, class T>
class has_inspect_overload {
private:
template <class U>
static auto sfinae(Inspector& x, U& y)
-> decltype(inspect(x, y), std::true_type{});
static std::false_type sfinae(Inspector&, ...);
using result_type
= decltype(sfinae(std::declval<Inspector&>(), std::declval<T&>()));
public:
static constexpr bool value = result_type::value;
};
/// Checks whether `T` provides an `inspect_value` overload for `Inspector`.
template <class Inspector, class T>
class has_inspect_value_overload {
private:
template <class U>
static auto sfinae(Inspector& x, U& y)
-> decltype(inspect_value(x, y), std::true_type{});
static std::false_type sfinae(Inspector&, ...);
using result_type
= decltype(sfinae(std::declval<Inspector&>(), std::declval<T&>()));
public:
static constexpr bool value = result_type::value;
};
/// Checks whether the inspector has a `builtin_inspect` overload for `T`.
template <class Inspector, class T>
class has_builtin_inspect {
private:
template <class I, class U>
static auto sfinae(I& f, U& x)
-> decltype(f.builtin_inspect(x), std::true_type{});
template <class I>
static std::false_type sfinae(I&, ...);
using sfinae_result
= decltype(sfinae(std::declval<Inspector&>(), std::declval<T&>()));
public:
static constexpr bool value = sfinae_result::value;
};
/// Checks whether inspectors are required to provide a `value` overload for T.
template <bool IsLoading, class T>
struct is_trivial_inspector_value;
template <class T>
struct is_trivial_inspector_value<true, T> {
static constexpr bool value = false;
};
template <class T>
struct is_trivial_inspector_value<false, T> {
static constexpr bool value = std::is_convertible<T, string_view>::value;
};
#define CAF_ADD_TRIVIAL_LOAD_INSPECTOR_VALUE(type) \
template <> \
struct is_trivial_inspector_value<true, type> { \
static constexpr bool value = true; \
};
#define CAF_ADD_TRIVIAL_SAVE_INSPECTOR_VALUE(type) \
template <> \
struct is_trivial_inspector_value<false, type> { \
static constexpr bool value = true; \
};
#define CAF_ADD_TRIVIAL_INSPECTOR_VALUE(type) \
CAF_ADD_TRIVIAL_LOAD_INSPECTOR_VALUE(type) \
CAF_ADD_TRIVIAL_SAVE_INSPECTOR_VALUE(type)
CAF_ADD_TRIVIAL_INSPECTOR_VALUE(bool);
CAF_ADD_TRIVIAL_INSPECTOR_VALUE(float);
CAF_ADD_TRIVIAL_INSPECTOR_VALUE(double);
CAF_ADD_TRIVIAL_INSPECTOR_VALUE(long double);
CAF_ADD_TRIVIAL_INSPECTOR_VALUE(std::u16string);
CAF_ADD_TRIVIAL_INSPECTOR_VALUE(std::u32string);
CAF_ADD_TRIVIAL_INSPECTOR_VALUE(std::vector<bool>);
CAF_ADD_TRIVIAL_INSPECTOR_VALUE(span<byte>);
CAF_ADD_TRIVIAL_SAVE_INSPECTOR_VALUE(span<const byte>);
CAF_ADD_TRIVIAL_LOAD_INSPECTOR_VALUE(std::string);
#undef CAF_ADD_TRIVIAL_INSPECTOR_VALUE
#undef CAF_ADD_TRIVIAL_SAVE_INSPECTOR_VALUE
#undef CAF_ADD_TRIVIAL_LOAD_INSPECTOR_VALUE
template <bool IsLoading, class T>
constexpr bool is_trivial_inspector_value_v
= is_trivial_inspector_value<IsLoading, T>::value;
/// Checks whether the inspector has an `opaque_value` overload for `T`.
template <class Inspector, class T>
class accepts_opaque_value {
private:
template <class F, class U>
static auto sfinae(F* f, U* x)
-> decltype(f->opaque_value(*x), std::true_type{});
static std::false_type sfinae(...);
using sfinae_result = decltype(sfinae(null_v<Inspector>, null_v<T>));
public:
static constexpr bool value = sfinae_result::value;
};
} // namespace caf::detail } // namespace caf::detail
#undef CAF_HAS_MEMBER_TRAIT #undef CAF_HAS_MEMBER_TRAIT
......
...@@ -111,6 +111,24 @@ public: ...@@ -111,6 +111,24 @@ public:
for_each_path_impl(g); for_each_path_impl(g);
} }
/// Applies `f` to each path.
template <class F>
void for_each_path(F f) const {
struct impl : path_visitor {
F fun;
impl(F x) : fun(std::move(x)) {
// nop
}
void operator()(outbound_path& x) override {
fun(const_cast<const outbound_path&>(x));
}
};
impl g{std::move(f)};
// This const_cast is safe, because we restore the const in our overload for
// operator() above.
const_cast<downstream_manager*>(this)->for_each_path_impl(g);
}
/// Returns all used slots. /// Returns all used slots.
std::vector<stream_slot> path_slots(); std::vector<stream_slot> path_slots();
......
...@@ -135,28 +135,33 @@ make(stream_slots slots, actor_addr addr, Ts&&... xs) { ...@@ -135,28 +135,33 @@ make(stream_slots slots, actor_addr addr, Ts&&... xs) {
/// @relates downstream_msg::batch /// @relates downstream_msg::batch
template <class Inspector> template <class Inspector>
typename Inspector::result_type bool inspect(Inspector& f, downstream_msg::batch& x) {
inspect(Inspector& f, downstream_msg::batch& x) { return f.object(x).pretty_name("batch").fields(f.field("size", x.xs_size),
return f(meta::type_name("batch"), meta::omittable(), x.xs_size, x.xs, x.id); f.field("xs", x.xs),
f.field("id", x.id));
} }
/// @relates downstream_msg::close /// @relates downstream_msg::close
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, downstream_msg::close&) { bool inspect(Inspector& f, downstream_msg::close& x) {
return f(meta::type_name("close")); return f.object(x).pretty_name("close").fields();
} }
/// @relates downstream_msg::forced_close /// @relates downstream_msg::forced_close
template <class Inspector> template <class Inspector>
typename Inspector::result_type bool inspect(Inspector& f, downstream_msg::forced_close& x) {
inspect(Inspector& f, downstream_msg::forced_close& x) { return f.object(x)
return f(meta::type_name("forced_close"), x.reason); .pretty_name("forced_close")
.fields(f.field("reason", x.reason));
} }
/// @relates downstream_msg /// @relates downstream_msg
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, downstream_msg& x) { bool inspect(Inspector& f, downstream_msg& x) {
return f(meta::type_name("downstream_msg"), x.slots, x.sender, x.content); return f.object(x)
.pretty_name("downstream_msg")
.fields(f.field("slots", x.slots), f.field("sender", x.sender),
f.field("content", x.content));
} }
} // namespace caf } // namespace caf
...@@ -28,10 +28,6 @@ ...@@ -28,10 +28,6 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/is_error_code_enum.hpp" #include "caf/is_error_code_enum.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/meta/load_callback.hpp"
#include "caf/meta/omittable_if_empty.hpp"
#include "caf/meta/save_callback.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/none.hpp" #include "caf/none.hpp"
#include "caf/type_id.hpp" #include "caf/type_id.hpp"
...@@ -67,6 +63,21 @@ namespace caf { ...@@ -67,6 +63,21 @@ namespace caf {
/// instead. /// instead.
class CAF_CORE_EXPORT error : detail::comparable<error> { class CAF_CORE_EXPORT error : detail::comparable<error> {
public: public:
// -- nested classes ---------------------------------------------------------
struct data {
uint8_t code;
type_id_t category;
message context;
template <class Inspector>
friend bool inspect(Inspector& f, data& x) {
return f.object(x).fields(f.field("code", x.code),
f.field("category", x.category),
f.field("context", x.context));
}
};
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
error() noexcept = default; error() noexcept = default;
...@@ -139,6 +150,11 @@ public: ...@@ -139,6 +150,11 @@ public:
return data_ == nullptr; return data_ == nullptr;
} }
/// Returns whether this error was default-constructed.
bool empty() const noexcept {
return data_ == nullptr;
}
int compare(const error&) const noexcept; int compare(const error&) const noexcept;
int compare(uint8_t code, type_id_t category) const noexcept; int compare(uint8_t code, type_id_t category) const noexcept;
...@@ -162,31 +178,8 @@ public: ...@@ -162,31 +178,8 @@ public:
// -- friend functions ------------------------------------------------------- // -- friend functions -------------------------------------------------------
template <class Inspector> template <class Inspector>
friend auto inspect(Inspector& f, error& x) { friend bool inspect(Inspector& f, error& x) {
using result_type = typename Inspector::result_type; return f.object(x).fields(f.field("data", x.data_));
if constexpr (Inspector::reads_state) {
if (!x) {
uint8_t code = 0;
return f(code);
}
return f(x.code(), x.category(), x.context());
} else {
uint8_t code = 0;
auto cb = meta::load_callback([&] {
if (code == 0) {
x.data_.reset();
if constexpr (std::is_same<result_type, void>::value)
return;
else
return result_type{};
}
if (!x.data_)
x.data_.reset(new data);
x.data_->code = code;
return f(x.data_->category, x.data_->context);
});
return f(code, cb);
}
} }
private: private:
...@@ -196,14 +189,6 @@ private: ...@@ -196,14 +189,6 @@ private:
error(uint8_t code, type_id_t category, message context); error(uint8_t code, type_id_t category, message context);
// -- nested classes ---------------------------------------------------------
struct data {
uint8_t code;
type_id_t category;
message context;
};
// -- member variables ------------------------------------------------------- // -- member variables -------------------------------------------------------
std::unique_ptr<data> data_; std::unique_ptr<data> data_;
......
...@@ -257,6 +257,16 @@ public: ...@@ -257,6 +257,16 @@ public:
return result; return result;
} }
size_t buffered(stream_slot slot) const noexcept override {
// We don't know which nested manager stores this path. Only one will give a
// valid answer, though. Everyone else always responds with 0. Hence, we can
// simply call all managers and sum up the results.
size_t result = 0;
for (auto ptr : ptrs_)
result += ptr->buffered(slot);
return result;
}
void clear_paths() override { void clear_paths() override {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
for (auto ptr : ptrs_) for (auto ptr : ptrs_)
......
...@@ -30,10 +30,10 @@ namespace caf { ...@@ -30,10 +30,10 @@ namespace caf {
// -- 1 param templates -------------------------------------------------------- // -- 1 param templates --------------------------------------------------------
template <class> class [[nodiscard]] error_code;
template <class> class behavior_type_of; template <class> class behavior_type_of;
template <class> class dictionary; template <class> class dictionary;
template <class> class downstream; template <class> class downstream;
template <class> class [[nodiscard]] error_code;
template <class> class expected; template <class> class expected;
template <class> class intrusive_cow_ptr; template <class> class intrusive_cow_ptr;
template <class> class intrusive_ptr; template <class> class intrusive_ptr;
...@@ -45,6 +45,7 @@ template <class> class stream_sink; ...@@ -45,6 +45,7 @@ template <class> class stream_sink;
template <class> class stream_source; template <class> class stream_source;
template <class> class weak_intrusive_ptr; template <class> class weak_intrusive_ptr;
template <class> struct inspector_access;
template <class> struct timeout_definition; template <class> struct timeout_definition;
template <class> struct type_id; template <class> struct type_id;
...@@ -81,6 +82,7 @@ template <class...> class variant; ...@@ -81,6 +82,7 @@ template <class...> class variant;
// -- classes ------------------------------------------------------------------ // -- classes ------------------------------------------------------------------
class [[nodiscard]] error;
class abstract_actor; class abstract_actor;
class abstract_group; class abstract_group;
class actor; class actor;
...@@ -106,12 +108,12 @@ class config_value; ...@@ -106,12 +108,12 @@ class config_value;
class deserializer; class deserializer;
class downstream_manager; class downstream_manager;
class downstream_manager_base; class downstream_manager_base;
class [[nodiscard]] error;
class event_based_actor; class event_based_actor;
class execution_unit; class execution_unit;
class forwarding_actor_proxy; class forwarding_actor_proxy;
class group; class group;
class group_module; class group_module;
class hashed_node_id;
class inbound_path; class inbound_path;
class ipv4_address; class ipv4_address;
class ipv4_endpoint; class ipv4_endpoint;
...@@ -126,6 +128,7 @@ class message_builder; ...@@ -126,6 +128,7 @@ class message_builder;
class message_handler; class message_handler;
class message_id; class message_id;
class node_id; class node_id;
class node_id_data;
class outbound_path; class outbound_path;
class proxy_registry; class proxy_registry;
class ref_counted; class ref_counted;
...@@ -163,12 +166,17 @@ struct illegal_message_element; ...@@ -163,12 +166,17 @@ struct illegal_message_element;
struct invalid_actor_addr_t; struct invalid_actor_addr_t;
struct invalid_actor_t; struct invalid_actor_t;
struct node_down_msg; struct node_down_msg;
struct none_t;
struct open_stream_msg; struct open_stream_msg;
struct prohibit_top_level_spawn_marker; struct prohibit_top_level_spawn_marker;
struct stream_slots; struct stream_slots;
struct timeout_msg; struct timeout_msg;
struct unit_t; struct unit_t;
struct upstream_msg; struct upstream_msg;
struct upstream_msg_ack_batch;
struct upstream_msg_ack_open;
struct upstream_msg_drop;
struct upstream_msg_forced_drop;
// -- free template functions -------------------------------------------------- // -- free template functions --------------------------------------------------
...@@ -353,14 +361,9 @@ class dynamic_message_data; ...@@ -353,14 +361,9 @@ class dynamic_message_data;
class group_manager; class group_manager;
class message_data; class message_data;
class private_thread; class private_thread;
class uri_impl;
struct meta_object; struct meta_object;
// enable intrusive_ptr<uri_impl> with forward declaration only
CAF_CORE_EXPORT void intrusive_ptr_add_ref(const uri_impl*);
CAF_CORE_EXPORT void intrusive_ptr_release(const uri_impl*);
// enable intrusive_cow_ptr<dynamic_message_data> with forward declaration only // enable intrusive_cow_ptr<dynamic_message_data> with forward declaration only
CAF_CORE_EXPORT void intrusive_ptr_add_ref(const dynamic_message_data*); CAF_CORE_EXPORT void intrusive_ptr_add_ref(const dynamic_message_data*);
CAF_CORE_EXPORT void intrusive_ptr_release(const dynamic_message_data*); CAF_CORE_EXPORT void intrusive_ptr_release(const dynamic_message_data*);
......
...@@ -80,14 +80,6 @@ public: ...@@ -80,14 +80,6 @@ public:
return ptr_ ? 1 : 0; return ptr_ ? 1 : 0;
} }
friend CAF_CORE_EXPORT error inspect(serializer&, group&);
friend CAF_CORE_EXPORT error_code<sec> inspect(binary_serializer&, group&);
friend CAF_CORE_EXPORT error inspect(deserializer&, group&);
friend CAF_CORE_EXPORT error_code<sec> inspect(binary_deserializer&, group&);
abstract_group* get() const noexcept { abstract_group* get() const noexcept {
return ptr_.get(); return ptr_.get();
} }
...@@ -122,6 +114,42 @@ public: ...@@ -122,6 +114,42 @@ public:
return this; return this;
} }
template <class Inspector>
friend bool inspect(Inspector& f, group& x) {
std::string module_name;
std::string group_name;
actor dispatcher;
if constexpr (!Inspector::is_loading) {
if (x) {
module_name = x.get()->module().name();
group_name = x.get()->identifier();
dispatcher = x.get()->dispatcher();
}
}
auto load_cb = [&] {
if constexpr (detail::has_context<Inspector>::value) {
auto ctx = f.context();
if (ctx != nullptr) {
if (auto grp = ctx->system().groups().get(module_name, group_name,
dispatcher)) {
x = std::move(*grp);
return true;
} else {
f.set_error(std::move(grp.error()));
return false;
}
}
}
f.emplace_error(sec::no_context);
return false;
};
return f.object(x)
.on_load(load_cb) //
.fields(f.field("module_name", module_name),
f.field("group_name", group_name),
f.field("dispatcher", dispatcher));
}
/// @endcond /// @endcond
private: private:
...@@ -140,11 +168,14 @@ CAF_CORE_EXPORT std::string to_string(const group& x); ...@@ -140,11 +168,14 @@ CAF_CORE_EXPORT std::string to_string(const group& x);
} // namespace caf } // namespace caf
namespace std { namespace std {
template <> template <>
struct hash<caf::group> { struct hash<caf::group> {
size_t operator()(const caf::group& x) const { size_t operator()(const caf::group& x) const {
// groups are singleton objects, the address is thus the best possible hash // Groups are singleton objects. Hence, we can simply use the address as
// hash value.
return !x ? 0 : reinterpret_cast<size_t>(x.get()); return !x ? 0 : reinterpret_cast<size_t>(x.get());
} }
}; };
} // namespace std } // namespace std
...@@ -79,6 +79,11 @@ public: ...@@ -79,6 +79,11 @@ public:
/// Returns the module named `name` if it exists, otherwise `none`. /// Returns the module named `name` if it exists, otherwise `none`.
optional<group_module&> get_module(const std::string& x) const; optional<group_module&> get_module(const std::string& x) const;
/// @private
expected<group> get(const std::string& module_name,
const std::string& group_identifier,
const caf::actor& dispatcher) const;
private: private:
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -221,6 +221,10 @@ public: ...@@ -221,6 +221,10 @@ public:
return cache_; return cache_;
} }
list_type& items() noexcept {
return list_;
}
// -- insertion -------------------------------------------------------------- // -- insertion --------------------------------------------------------------
/// Appends `ptr` to the queue. /// Appends `ptr` to the queue.
......
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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