Commit ade1b959 authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'topic/filter-and-match' into develop

parents 5370dd5d 42035bf4
......@@ -55,7 +55,9 @@ void ChatWidget::sendChatMessage() {
});
QString line = input()->text();
if (line.startsWith('/')) {
match_split(line.midRef(1).toUtf8().constData(), ' ') (
vector<string> words;
split(words, line.midRef(1).toUtf8().constData(), is_any_of(" "));
message_builder(words.begin(), words.end()).apply({
on("join", arg_match) >> [=](const string& mod, const string& g) {
group gptr;
try { gptr = group::get(mod, g); }
......@@ -74,7 +76,7 @@ void ChatWidget::sendChatMessage() {
"/join <module> <group id>\n"
"/setName <new name>\n");
}
);
});
return;
}
if (m_name.empty()) {
......
......@@ -21,89 +21,59 @@
#include <QApplication>
#include "caf/all.hpp"
#include "cppa/opt.hpp"
#include "ui_chatwindow.h" // auto generated from chatwindow.ui
using namespace std;
using namespace caf;
/*
namespace {
struct line { string str; };
istream& operator>>(istream& is, line& l) {
getline(is, l.str);
return is;
}
any_tuple s_last_line;
any_tuple split_line(const line& l) {
vector<string> result;
stringstream strs(l.str);
string tmp;
while (getline(strs, tmp, ' ')) {
if (!tmp.empty()) result.push_back(std::move(tmp));
}
s_last_line = any_tuple::view(std::move(result));
return s_last_line;
}
} // namespace <anonymous>
*/
int main(int argc, char** argv) {
string name;
string group_id;
options_description desc;
bool args_valid = match_stream<string>(argv + 1, argv + argc) (
on_opt1('n', "name", &desc, "set name") >> rd_arg(name),
on_opt1('g', "group", &desc, "join group <arg1>") >> rd_arg(group_id),
on_opt0('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
);
group gptr;
// evaluate group parameter
if (!group_id.empty()) {
auto p = group_id.find(':');
if (p == std::string::npos) {
cerr << "*** error parsing argument " << group_id
<< ", expected format: <module_name>:<group_id>";
}
else {
try {
gptr = group::get(group_id.substr(0, p),
group_id.substr(p + 1));
}
catch (exception& e) {
ostringstream err;
cerr << "*** exception: group::get(\"" << group_id.substr(0, p)
<< "\", \"" << group_id.substr(p + 1) << "\") failed; "
<< to_verbose_string(e) << endl;
}
}
}
if (!args_valid) print_desc_and_exit(&desc)();
QApplication app(argc, argv);
app.setQuitOnLastWindowClosed(true);
QMainWindow mw;
Ui::ChatWindow helper;
helper.setupUi(&mw);
auto client = helper.chatwidget->as_actor();
if (!name.empty()) {
send_as(client, client, atom("setName"), move(name));
}
if (gptr) {
send_as(client, client, atom("join"), gptr);
string name;
string group_id;
auto res = message_builder(argv + 1, argv + argc).filter_cli({
{"name,n", "set chat name", name},
{"group,g", "join chat group", group_id}
});
if (!res.remainder.empty()) {
std::cerr << res.helptext << std::endl;
return 1;
}
if (res.opts.count("help") > 0) {
return 0;
}
group gptr;
// evaluate group parameter
if (!group_id.empty()) {
auto p = group_id.find(':');
if (p == std::string::npos) {
cerr << "*** error parsing argument " << group_id
<< ", expected format: <module_name>:<group_id>";
} else {
try {
gptr = group::get(group_id.substr(0, p), group_id.substr(p + 1));
} catch (exception& e) {
ostringstream err;
cerr << "*** exception: group::get(\"" << group_id.substr(0, p)
<< "\", \"" << group_id.substr(p + 1) << "\") failed; "
<< to_verbose_string(e) << endl;
}
}
mw.show();
auto res = app.exec();
shutdown();
await_all_actors_done();
return res;
}
QApplication app(argc, argv);
app.setQuitOnLastWindowClosed(true);
QMainWindow mw;
Ui::ChatWindow helper;
helper.setupUi(&mw);
auto client = helper.chatwidget->as_actor();
if (!name.empty()) {
send_as(client, client, atom("setName"), move(name));
}
if (gptr) {
send_as(client, client, atom("join"), gptr);
}
mw.show();
auto app_res = app.exec();
await_all_actors_done();
shutdown();
return app_res;
}
......@@ -21,9 +21,6 @@
#include "caf/all.hpp"
#include "caf/io/all.hpp"
// the options_description API is deprecated
#include "cppa/opt.hpp"
using namespace std;
using namespace caf;
......@@ -127,7 +124,9 @@ void client_repl(const string& host, uint16_t port) {
anon_send_exit(client, exit_reason::user_shutdown);
return;
} else if (equal(begin(connect), end(connect) - 1, begin(line))) {
match_split(line, ' ') (
vector<string> words;
split(words, line, is_any_of(" "));
message_builder(words.begin(), words.end()).apply({
on("connect", arg_match) >> [&](string& nhost, string& sport) {
try {
auto lport = std::stoul(sport);
......@@ -147,7 +146,7 @@ void client_repl(const string& host, uint16_t port) {
others() >> [] {
cout << "*** usage: connect <host> <port>" << endl;
}
);
});
} else {
auto toint = [](const string& str) -> optional<int> {
try { return {std::stoi(str)}; }
......@@ -183,41 +182,40 @@ void client_repl(const string& host, uint16_t port) {
}
int main(int argc, char** argv) {
string mode;
string host;
uint16_t port = 0;
options_description desc;
auto set_mode = [&](const string& arg) -> function<bool()> {
return [arg, &mode]() -> bool {
if (!mode.empty()) {
cerr << "mode already set to " << mode << endl;
return false;
}
mode = move(arg);
return true;
};
};
string copts = "client options";
string sopts = "server options";
bool args_valid = match_stream<string> (argv + 1, argv + argc) (
on_opt1('p', "port", &desc, "set port") >> rd_arg(port),
on_opt1('H', "host", &desc, "set host (default: localhost)", copts) >> rd_arg(host),
on_opt0('s', "server", &desc, "run in server mode", sopts) >> set_mode("server"),
on_opt0('c', "client", &desc, "run in client mode", copts) >> set_mode("client"),
on_opt0('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
);
if (!args_valid || port == 0 || mode.empty()) {
if (port == 0) cerr << "*** no port specified" << endl;
if (mode.empty()) cerr << "*** no mode specified" << endl;
cerr << endl;
auto description_printer = print_desc(&desc, cerr);
description_printer();
return -1;
string host = "localhost";
auto res = message_builder(argv + 1, argv + argc).to_message().filter_cli({
{"port,p", "set port (either to publish at or to connect to)", port},
{"host,H", "set host (client mode only, default: localhost)", host},
{"server,s", "run in server mode"},
{"client,c", "run in client mode"}
});
if (res.opts.count("help") > 0) {
return 0;
}
if (!res.remainder.empty()) {
cerr << "*** invalid command line options" << endl << res.helptext << endl;
return 1;
}
bool is_server = res.opts.count("server") > 0;
if (is_server == (res.opts.count("client") > 0)) {
if (is_server) {
cerr << "*** cannot be server and client at the same time" << endl;
} else {
cerr << "*** either --server or --client option must be set" << endl;
}
return 1;
}
if (!is_server && port == 0) {
cerr << "*** no port to server specified" << endl;
return 1;
}
if (mode == "server") {
if (is_server) {
try {
// try to publish math actor at given port
io::publish(spawn(calculator), port);
cout << "*** try publish at port " << port << endl;
auto p = io::publish(spawn(calculator), port);
cout << "*** server successfully published at port " << p << endl;
}
catch (exception& e) {
cerr << "*** unable to publish math actor at port " << port << "\n"
......@@ -226,10 +224,8 @@ int main(int argc, char** argv) {
}
}
else {
if (host.empty()) host = "localhost";
client_repl(host, port);
}
await_all_actors_done();
shutdown();
return 0;
}
......@@ -18,8 +18,7 @@
#include "caf/all.hpp"
#include "caf/io/all.hpp"
// the options_description API is deprecated
#include "cppa/opt.hpp"
#include "caf/string_algorithms.hpp"
using namespace std;
using namespace caf;
......@@ -80,14 +79,16 @@ void client(event_based_actor* self, const string& name) {
int main(int argc, char** argv) {
string name;
string group_id;
options_description desc;
bool args_valid = match_stream<string>(argv + 1, argv + argc) (
on_opt1('n', "name", &desc, "set name") >> rd_arg(name),
on_opt1('g', "group", &desc, "join group <arg1>") >> rd_arg(group_id),
on_opt0('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
);
if (!args_valid) {
print_desc_and_exit(&desc)();
auto res = message_builder(argv + 1, argv + argc).filter_cli({
{"name,n", "set name", name},
{"group,g", "join group", group_id}
});
if (!res.remainder.empty()) {
std::cout << res.helptext << std::endl;
return 1;
}
if (res.opts.count("help") > 0) {
return 0;
}
while (name.empty()) {
cout << "please enter your name: " << flush;
......@@ -128,35 +129,39 @@ int main(int argc, char** argv) {
return none;
};
};
istream_iterator<line> lines(cin);
istream_iterator<line> eof;
match_each (lines, eof, split_line) (
on("/join", arg_match) >> [&](const string& mod, const string& id) {
try {
group grp = (mod == "remote") ? io::remote_group(id)
: group::get(mod, id);
anon_send(client_actor, join_atom::value, grp);
}
catch (exception& e) {
cerr << "*** exception: " << to_verbose_string(e) << endl;
}
},
on("/quit") >> [&] {
// close STDIN; causes this match loop to quit
cin.setstate(ios_base::eofbit);
},
on(starts_with("/"), any_vals) >> [&] {
cout << "*** available commands:\n"
" /join <module> <group> join a new chat channel\n"
" /quit quit the program\n"
" /help print this text\n" << flush;
},
others() >> [&] {
if (!s_last_line.empty()) {
anon_send(client_actor, broadcast_atom::value, s_last_line);
vector<string> words;
for (istream_iterator<line> i(cin); i != eof; ++i) {
words.clear();
split(words, i->str, is_any_of(" "));
message_builder(words.begin(), words.end()).apply({
on("/join", arg_match) >> [&](const string& mod, const string& id) {
try {
group grp = (mod == "remote") ? io::remote_group(id)
: group::get(mod, id);
anon_send(client_actor, join_atom::value, grp);
}
catch (exception& e) {
cerr << "*** exception: " << to_verbose_string(e) << endl;
}
},
on("/quit") >> [&] {
// close STDIN; causes this match loop to quit
cin.setstate(ios_base::eofbit);
},
on(starts_with("/"), any_vals) >> [&] {
cout << "*** available commands:\n"
" /join <module> <group> join a new chat channel\n"
" /quit quit the program\n"
" /help print this text\n" << flush;
},
others() >> [&] {
if (!s_last_line.empty()) {
anon_send(client_actor, broadcast_atom::value, s_last_line);
}
}
}
);
});
}
// force actor to quit
anon_send_exit(client_actor, exit_reason::user_shutdown);
await_all_actors_done();
......
......@@ -52,14 +52,12 @@ set (LIBCAF_CORE_SRCS
src/local_actor.cpp
src/logging.cpp
src/mailbox_element.cpp
src/match.cpp
src/memory.cpp
src/memory_managed.cpp
src/message.cpp
src/message_builder.cpp
src/message_data.cpp
src/message_handler.cpp
src/message_iterator.cpp
src/node_id.cpp
src/ref_counted.cpp
src/response_promise.cpp
......
......@@ -100,11 +100,6 @@ class abstract_actor : public abstract_channel {
*/
size_t detach(const attachable::token& what);
template <class T>
size_t detach(const T& what) {
return detach(attachable::token{typeid(T), &what});
}
enum linking_operation {
establish_link_op,
establish_backlink_op,
......@@ -281,8 +276,6 @@ class abstract_actor : public abstract_channel {
// identifies the execution unit this actor is currently executed by
execution_unit* m_host;
// stores several actor-related flags
int m_flags;
};
} // namespace caf
......
......@@ -34,6 +34,9 @@ namespace caf {
*/
class abstract_channel : public ref_counted {
public:
friend class abstract_actor;
friend class abstract_group;
virtual ~abstract_channel();
/**
......@@ -54,17 +57,34 @@ class abstract_channel : public ref_counted {
*/
bool is_remote() const;
protected:
enum channel_type_flag {
is_abstract_actor_flag = 0x100000,
is_abstract_group_flag = 0x200000
};
abstract_channel(size_t initial_ref_count = 0);
inline bool is_abstract_actor() const {
return m_flags & static_cast<int>(is_abstract_actor_flag);
}
abstract_channel(node_id nid, size_t initial_ref_count = 0);
inline bool is_abstract_group() const {
return m_flags & static_cast<int>(is_abstract_group_flag);
}
private:
protected:
/**
* Accumulates several state and type flags. Subtypes may use only the
* first 20 bits, i.e., the bitmask 0xFFF00000 is reserved for
* channel-related flags.
*/
int m_flags;
private:
// can only be called from abstract_actor and abstract_group
abstract_channel(channel_type_flag subtype, size_t initial_ref_count = 0);
abstract_channel(channel_type_flag subtype, node_id nid,
size_t initial_ref_count = 0);
// identifies the node of this channel
node_id m_node;
};
/**
......
......@@ -59,6 +59,7 @@ class abstract_group : public abstract_channel {
struct subscription_token {
intrusive_ptr<abstract_group> group;
static constexpr size_t token_type = attachable::token::subscription;
};
class subscription_predicate {
......
......@@ -26,7 +26,6 @@
#include "caf/unit.hpp"
#include "caf/actor.hpp"
#include "caf/group.hpp"
#include "caf/match.hpp"
#include "caf/spawn.hpp"
#include "caf/config.hpp"
#include "caf/either.hpp"
......
......@@ -41,25 +41,40 @@ class attachable {
attachable& operator=(const attachable&) = delete;
/**
* Represents a pointer to a value with its RTTI.
* Represents a pointer to a value with its subtype as type ID number.
*/
struct token {
/**
* Identifies a non-matchable subtype.
*/
static constexpr size_t anonymous = 0;
/**
* Identifies `abstract_group::subscription`.
*/
static constexpr size_t subscription = 1;
/**
* Identifies `default_attachable::observe_token`.
*/
static constexpr size_t observer = 2;
template <class T>
token(const T& tk) : subtype(typeid(T)), ptr(&tk) {
token(const T& tk) : subtype(T::token_type), ptr(&tk) {
// nop
}
/**
* Denotes the type of ptr.
*/
const std::type_info& subtype;
size_t subtype;
/**
* Any value, used to identify attachable instances.
*/
const void* ptr;
token(const std::type_info& subtype, const void* ptr);
token(size_t subtype, const void* ptr);
};
virtual ~attachable();
......@@ -89,7 +104,7 @@ class attachable {
*/
template <class T>
bool matches(const T& what) {
return matches(token{typeid(T), &what});
return matches(token{T::token_type, &what});
}
std::unique_ptr<attachable> next;
......
......@@ -35,6 +35,7 @@ class default_attachable : public attachable {
struct observe_token {
actor_addr observer;
observe_type type;
static constexpr size_t token_type = attachable::token::observer;
};
void actor_exited(abstract_actor* self, uint32_t reason) override;
......
......@@ -37,19 +37,19 @@ namespace detail {
*/
template <class T>
class abstract_uniform_type_info : public uniform_type_info {
public:
bool equal_to(const std::type_info& tinfo) const override {
return typeid(T) == tinfo;
const char* name() const override {
return m_name.c_str();
}
const char* name() const { return m_name.c_str(); }
message as_message(void* instance) const override {
return make_message(deref(instance));
}
bool equal_to(const std::type_info& tinfo) const override {
return m_native == &tinfo || *m_native == tinfo;
}
bool equals(const void* lhs, const void* rhs) const override {
return eq(deref(lhs), deref(rhs));
}
......@@ -59,25 +59,30 @@ class abstract_uniform_type_info : public uniform_type_info {
}
protected:
abstract_uniform_type_info(std::string tname) : m_name(std::move(tname)) {
abstract_uniform_type_info(std::string tname)
: m_name(std::move(tname)),
m_native(&typeid(T)) {
// nop
}
static inline const T& deref(const void* ptr) {
static const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(ptr);
}
static inline T& deref(void* ptr) { return *reinterpret_cast<T*>(ptr); }
static T& deref(void* ptr) {
return *reinterpret_cast<T*>(ptr);
}
// can be overridden in subclasses to compare POD types
// by comparing each individual member
virtual bool pod_mems_equals(const T&, const T&) const { return false; }
virtual bool pod_mems_equals(const T&, const T&) const {
return false;
}
std::string m_name;
const std::type_info* m_native;
private:
template <class C>
typename std::enable_if<std::is_empty<C>::value, bool>::type
eq(const C&, const C&) const {
......@@ -99,7 +104,6 @@ class abstract_uniform_type_info : public uniform_type_info {
eq(const C& lhs, const C& rhs) const {
return pod_mems_equals(lhs, rhs);
}
};
} // namespace detail
......
......@@ -47,28 +47,16 @@ class decorated_tuple : public message_data {
using pointer = message_data::ptr;
using rtti = const std::type_info*;
// creates a dynamically typed subtuple from `d` with an offset
// creates a typed subtuple from `d` with mapping `v`
static inline pointer create(pointer d, vector_type v) {
return pointer{new decorated_tuple(std::move(d), std::move(v))};
}
// creates a statically typed subtuple from `d` with an offset
static inline pointer create(pointer d, rtti ti, vector_type v) {
return pointer{new decorated_tuple(std::move(d), ti, std::move(v))};
}
// creates a dynamically typed subtuple from `d` with an offset
// creates a typed subtuple from `d` with an offset
static inline pointer create(pointer d, size_t offset) {
return pointer{new decorated_tuple(std::move(d), offset)};
}
// creates a statically typed subtuple from `d` with an offset
static inline pointer create(pointer d, rtti ti, size_t offset) {
return pointer{new decorated_tuple(std::move(d), ti, offset)};
}
void* mutable_at(size_t pos) override;
size_t size() const override;
......@@ -77,17 +65,20 @@ class decorated_tuple : public message_data {
const void* at(size_t pos) const override;
const uniform_type_info* type_at(size_t pos) const override;
bool match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const override;
uint32_t type_token() const override;
const std::string* tuple_type_names() const override;
const char* uniform_name_at(size_t pos) const override;
rtti type_token() const override;
uint16_t type_nr_at(size_t pos) const override;
private:
pointer m_decorated;
rtti m_token;
vector_type m_mapping;
uint32_t m_type_token;
void init();
......@@ -95,12 +86,8 @@ class decorated_tuple : public message_data {
decorated_tuple(pointer, size_t);
decorated_tuple(pointer, rtti, size_t);
decorated_tuple(pointer, vector_type&&);
decorated_tuple(pointer, rtti, vector_type&&);
decorated_tuple(const decorated_tuple&) = default;
};
......
......@@ -30,7 +30,6 @@
#include "caf/deserializer.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/types_array.hpp"
#include "caf/detail/abstract_uniform_type_info.hpp"
......@@ -164,7 +163,7 @@ class default_serialize_policy {
template <class T>
void simpl(const T& val, serializer* s, recursive_impl) const {
static_types_array<T>::arr[0]->serialize(&val, s);
uniform_typeid<T>()->serialize(&val, s);
}
template <class T>
......@@ -217,7 +216,7 @@ class default_serialize_policy {
template <class T>
void dimpl(T& storage, deserializer* d, recursive_impl) const {
static_types_array<T>::arr[0]->deserialize(&storage, d);
uniform_typeid<T>()->deserialize(&storage, d);
}
};
......
......@@ -39,6 +39,7 @@ struct functor_attachable : attachable {
void actor_exited(abstract_actor* self, uint32_t reason) override {
m_functor(self, reason);
}
static constexpr size_t token_type = attachable::token::anonymous;
};
template <class F>
......
......@@ -31,20 +31,12 @@
#include "caf/uniform_type_info.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/message_iterator.hpp"
namespace caf {
namespace detail {
class message_data : public ref_counted {
using super = ref_counted;
public:
message_data(bool dynamically_typed);
message_data(const message_data& other);
// mutators
virtual void* mutable_at(size_t pos) = 0;
virtual void* mutable_native_data();
......@@ -53,42 +45,29 @@ class message_data : public ref_counted {
virtual size_t size() const = 0;
virtual message_data* copy() const = 0;
virtual const void* at(size_t pos) const = 0;
virtual const uniform_type_info* type_at(size_t pos) const = 0;
virtual const std::string* tuple_type_names() const = 0;
std::string tuple_type_names() const;
/**
* Tries to match element at position `pos` to given RTTI.
* @param pos Index of element in question.
* @param typenr Number of queried type or `0` for custom types.
* @param rtti Queried type or `nullptr` for builtin types.
*/
virtual bool match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const = 0;
virtual uint32_t type_token() const = 0;
// returns either tdata<...> object or nullptr (default) if tuple
// is not a 'native' implementation
virtual const void* native_data() const;
// Identifies the type of the implementation.
// A statically typed tuple implementation can use some optimizations,
// e.g., "impl_type() == statically_typed" implies that type_token()
// identifies all possible instances of a given tuple implementation
inline bool dynamically_typed() const { return m_is_dynamic; }
virtual const char* uniform_name_at(size_t pos) const = 0;
// uniquely identifies this category (element types) of messages
// override this member function only if impl_type() == statically_typed
// (default returns &typeid(void))
virtual const std::type_info* type_token() const;
virtual uint16_t type_nr_at(size_t pos) const = 0;
bool equals(const message_data& other) const;
using const_iterator = message_iterator;
inline const_iterator begin() const {
return {this};
}
inline const_iterator cbegin() const {
return {this};
}
inline const_iterator end() const {
return {this, size()};
}
inline const_iterator cend() const {
return {this, size()};
}
class ptr {
public:
......@@ -125,15 +104,8 @@ class message_data : public ref_counted {
intrusive_ptr<message_data> m_ptr;
};
private:
bool m_is_dynamic;
};
std::string get_tuple_type_names(const detail::message_data&);
} // namespace detail
} // namespace caf
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_MESSAGE_ITERATOR_HPP
#define CAF_DETAIL_MESSAGE_ITERATOR_HPP
#include <cstddef>
#include "caf/fwd.hpp"
namespace caf {
namespace detail {
class message_data;
class message_iterator {
public:
using pointer = message_data*;
using const_pointer = const message_data*;
message_iterator(const_pointer data, size_t pos = 0);
message_iterator(const message_iterator&) = default;
message_iterator& operator=(const message_iterator&) = default;
inline message_iterator& operator++() {
++m_pos;
return *this;
}
inline message_iterator& operator--() {
--m_pos;
return *this;
}
inline message_iterator operator+(size_t offset) {
return {m_data, m_pos + offset};
}
inline message_iterator& operator+=(size_t offset) {
m_pos += offset;
return *this;
}
inline message_iterator operator-(size_t offset) {
return {m_data, m_pos - offset};
}
inline message_iterator& operator-=(size_t offset) {
m_pos -= offset;
return *this;
}
inline size_t position() const {
return m_pos;
}
inline const_pointer data() const {
return m_data;
}
const void* value() const;
const uniform_type_info* type() const;
inline message_iterator& operator*() {
return *this;
}
private:
size_t m_pos;
const message_data* m_data;
};
inline bool operator==(const message_iterator& lhs,
const message_iterator& rhs) {
return lhs.data() == rhs.data() && lhs.position() == rhs.position();
}
inline bool operator!=(const message_iterator& lhs,
const message_iterator& rhs) {
return !(lhs == rhs);
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_MESSAGE_ITERATOR_HPP
......@@ -26,45 +26,53 @@
#include "caf/atom.hpp"
#include "caf/message.hpp"
#include "caf/uniform_typeid.hpp"
#include "caf/wildcard_position.hpp"
#include "caf/detail/type_nr.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/pseudo_tuple.hpp"
namespace caf {
namespace detail {
bool match_element(const atom_value&, const std::type_info* type,
const message_iterator& iter, void** storage);
bool match_atom_constant(const atom_value&, const std::type_info* type,
const message_iterator& iter, void** storage);
struct meta_element {
atom_value v;
uint16_t typenr;
const std::type_info* type;
bool (*fun)(const atom_value&, const std::type_info*,
const message_iterator&, void**);
bool (*fun)(const meta_element&, const message&, size_t, void**);
};
template <class T>
bool match_element(const meta_element&, const message&, size_t, void**);
bool match_atom_constant(const meta_element&, const message&, size_t, void**);
template <class T, uint16_t TN = detail::type_nr<T>::value>
struct meta_element_factory {
static meta_element create() {
return {static_cast<atom_value>(0), &typeid(T), match_element};
return {static_cast<atom_value>(0), TN, nullptr, match_element};
}
};
template <class T>
struct meta_element_factory<T, 0> {
static meta_element create() {
return {static_cast<atom_value>(0), 0, &typeid(T), match_element};
}
};
template <atom_value V>
struct meta_element_factory<atom_constant<V>> {
struct meta_element_factory<atom_constant<V>, type_nr<atom_value>::value> {
static meta_element create() {
return {V, &typeid(atom_value), match_atom_constant};
return {V, detail::type_nr<atom_value>::value,
nullptr, match_atom_constant};
}
};
template <>
struct meta_element_factory<anything> {
struct meta_element_factory<anything, 0> {
static meta_element create() {
return {static_cast<atom_value>(0), nullptr, nullptr};
return {static_cast<atom_value>(0), 0, nullptr, nullptr};
}
};
......@@ -79,10 +87,8 @@ struct meta_elements<type_list<Ts...>> {
}
};
bool try_match(const message& msg,
const meta_element* pattern_begin,
size_t pattern_size,
void** out = nullptr);
bool try_match(const message& msg, const meta_element* pattern_begin,
size_t pattern_size, void** out);
} // namespace detail
} // namespace caf
......
......@@ -25,7 +25,6 @@
#include "caf/detail/type_list.hpp"
#include "caf/detail/types_array.hpp"
#include "caf/detail/message_data.hpp"
namespace caf {
......@@ -53,82 +52,105 @@ struct tup_ptr_access<Pos, Max, false> {
}
};
using tuple_vals_rtti = std::pair<uint16_t, const std::type_info*>;
template <class T, uint16_t N = type_nr<T>::value>
struct tuple_vals_type_helper {
static tuple_vals_rtti get() {
return {N, nullptr};
}
};
template <class T>
struct tuple_vals_type_helper<T, 0> {
static tuple_vals_rtti get() {
return {0, &typeid(T)};
}
};
template <class... Ts>
class tuple_vals : public message_data {
public:
static_assert(sizeof...(Ts) > 0, "tuple_vals is not allowed to be empty");
using super = message_data;
public:
using data_type = std::tuple<Ts...>;
using element_types = types_array<Ts...>;
tuple_vals(const tuple_vals&) = default;
template <class... Us>
tuple_vals(Us&&... args)
: super(false), m_data(std::forward<Us>(args)...) {}
: m_data(std::forward<Us>(args)...),
m_types{{tuple_vals_type_helper<Ts>::get()...}} {
// nop
}
const void* native_data() const { return &m_data; }
const void* native_data() const override {
return &m_data;
}
void* mutable_native_data() { return &m_data; }
void* mutable_native_data() override {
return &m_data;
}
inline data_type& data() { return m_data; }
data_type& data() {
return m_data;
}
inline const data_type& data() const { return m_data; }
const data_type& data() const {
return m_data;
}
size_t size() const { return sizeof...(Ts); }
size_t size() const override {
return sizeof...(Ts);
}
tuple_vals* copy() const { return new tuple_vals(*this); }
tuple_vals* copy() const override {
return new tuple_vals(*this);
}
const void* at(size_t pos) const {
const void* at(size_t pos) const override {
CAF_REQUIRE(pos < size());
return tup_ptr_access<0, sizeof...(Ts)>::get(pos, m_data);
}
void* mutable_at(size_t pos) {
void* mutable_at(size_t pos) override {
CAF_REQUIRE(pos < size());
return const_cast<void*>(at(pos));
}
const uniform_type_info* type_at(size_t pos) const {
bool match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const override {
CAF_REQUIRE(pos < size());
return m_types[pos];
auto& et = m_types[pos];
if (et.first != typenr) {
return false;
}
return et.first != 0 || et.second == rtti || *et.second == *rtti;
}
bool equals(const message_data& other) const {
if (size() != other.size()) return false;
const tuple_vals* o = dynamic_cast<const tuple_vals*>(&other);
if (o) {
return m_data == (o->m_data);
}
return message_data::equals(other);
uint32_t type_token() const override {
return make_type_token<Ts...>();
}
const std::type_info* type_token() const {
return detail::static_type_list<Ts...>::list;
const char* uniform_name_at(size_t pos) const override {
auto& et = m_types[pos];
if (et.first != 0) {
return numbered_type_names[et.first - 1];
}
return uniform_typeid(*et.second)->name();
}
const std::string* tuple_type_names() const override {
// produced name is equal for all instances
static std::string result = get_tuple_type_names(*this);
return &result;
uint16_t type_nr_at(size_t pos) const override {
return m_types[pos].first;
}
private:
data_type m_data;
static types_array<Ts...> m_types;
std::array<tuple_vals_rtti, sizeof...(Ts)> m_types;
};
template <class... Ts>
types_array<Ts...> tuple_vals<Ts...>::m_types;
} // namespace detail
} // namespace caf
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_TYPE_NR_HPP
#define CAF_DETAIL_TYPE_NR_HPP
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdint>
#include "caf/fwd.hpp"
#include "caf/atom.hpp"
#include "caf/detail/type_list.hpp"
namespace caf {
namespace detail {
#define CAF_DETAIL_TYPE_NR(number, tname) \
template <> \
struct type_nr<tname> { \
static constexpr uint16_t value = number; \
};
template <class T,
bool IntegralConstant = std::is_integral<T>::value,
size_t = sizeof(T)>
struct type_nr_helper {
static constexpr uint16_t value = 0;
};
template <class T>
struct type_nr {
static constexpr uint16_t value = type_nr_helper<T>::value;
};
template <>
struct type_nr<void> {
static constexpr uint16_t value = 0;
};
using strmap = std::map<std::string, std::string>;
// WARNING: types are sorted by uniform name
CAF_DETAIL_TYPE_NR( 1, actor) // @actor
CAF_DETAIL_TYPE_NR( 2, actor_addr) // @addr
CAF_DETAIL_TYPE_NR( 3, atom_value) // @atom
CAF_DETAIL_TYPE_NR( 4, channel) // @channel
CAF_DETAIL_TYPE_NR( 5, std::vector<char>) // @charbuf
CAF_DETAIL_TYPE_NR( 6, down_msg) // @down
CAF_DETAIL_TYPE_NR( 7, duration) // @duration
CAF_DETAIL_TYPE_NR( 8, exit_msg) // @exit
CAF_DETAIL_TYPE_NR( 9, group) // @group
CAF_DETAIL_TYPE_NR(10, group_down_msg) // @group_down
CAF_DETAIL_TYPE_NR(11, int16_t) // @i16
CAF_DETAIL_TYPE_NR(12, int32_t) // @i32
CAF_DETAIL_TYPE_NR(13, int64_t) // @i64
CAF_DETAIL_TYPE_NR(14, int8_t) // @i8
CAF_DETAIL_TYPE_NR(15, long double) // @ldouble
CAF_DETAIL_TYPE_NR(16, message) // @message
CAF_DETAIL_TYPE_NR(17, message_id) // @message_id
CAF_DETAIL_TYPE_NR(18, node_id) // @node
CAF_DETAIL_TYPE_NR(19, std::string) // @str
CAF_DETAIL_TYPE_NR(20, strmap) // @strmap
CAF_DETAIL_TYPE_NR(21, std::set<std::string>) // @strset
CAF_DETAIL_TYPE_NR(22, std::vector<std::string>) // @strvec
CAF_DETAIL_TYPE_NR(23, sync_exited_msg) // @sync_exited
CAF_DETAIL_TYPE_NR(24, sync_timeout_msg) // @sync_timeout
CAF_DETAIL_TYPE_NR(25, timeout_msg) // @timeout
CAF_DETAIL_TYPE_NR(26, uint16_t) // @u16
CAF_DETAIL_TYPE_NR(27, std::u16string) // @u16_str
CAF_DETAIL_TYPE_NR(28, uint32_t) // @u32
CAF_DETAIL_TYPE_NR(29, std::u32string) // @u32_str
CAF_DETAIL_TYPE_NR(30, uint64_t) // @u64
CAF_DETAIL_TYPE_NR(31, uint8_t) // @u8
CAF_DETAIL_TYPE_NR(32, unit_t) // @unit
CAF_DETAIL_TYPE_NR(33, bool) // bool
CAF_DETAIL_TYPE_NR(34, double) // double
CAF_DETAIL_TYPE_NR(35, float) // float
template <atom_value V>
struct type_nr<atom_constant<V>> {
static constexpr uint16_t value = type_nr<atom_value>::value;
};
static constexpr size_t type_nrs = 36;
extern const char* numbered_type_names[];
template <class T>
struct type_nr_helper<T, true, 1> {
static constexpr uint16_t value = std::is_signed<T>::value
? type_nr<int8_t>::value
: type_nr<uint8_t>::value;
};
template <class T>
struct type_nr_helper<T, true, 2> {
static constexpr uint16_t value = std::is_signed<T>::value
? type_nr<int16_t>::value
: type_nr<uint16_t>::value;
};
template <class T>
struct type_nr_helper<T, true, 4> {
static constexpr uint16_t value = std::is_signed<T>::value
? type_nr<int32_t>::value
: type_nr<uint32_t>::value;
};
template <class T>
struct type_nr_helper<T, true, 8> {
static constexpr uint16_t value = std::is_signed<T>::value
? type_nr<int64_t>::value
: type_nr<uint64_t>::value;
};
template <uint32_t R, uint16_t... Is>
struct type_token_helper;
template <uint32_t R>
struct type_token_helper<R> : std::integral_constant<uint32_t, R> {
// nop
};
template <uint32_t R, uint16_t I, uint16_t... Is>
struct type_token_helper<R, I, Is...> : type_token_helper<(R << 6) | I, Is...> {
// nop
};
template <class... Ts>
constexpr uint32_t make_type_token() {
return type_token_helper<0xFFFFFFFF, type_nr<Ts>::value...>::value;
}
template <class T>
struct make_type_token_from_list_helper;
template <class... Ts>
struct make_type_token_from_list_helper<type_list<Ts...>>
: type_token_helper<0xFFFFFFFF, type_nr<Ts>::value...> {
// nop
};
template <class T>
constexpr uint32_t make_type_token_from_list() {
return make_type_token_from_list_helper<T>::value;
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_TYPE_NR_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_TYPES_ARRAY_HPP
#define CAF_DETAIL_TYPES_ARRAY_HPP
#include <atomic>
#include <typeinfo>
#include "caf/uniform_typeid.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
namespace caf {
namespace detail {
enum type_info_impl {
std_tinf,
caf_tinf
};
// some metaprogramming utility
template <type_info_impl What, bool IsBuiltin, typename T>
struct ta_util;
template <bool IsBuiltin, typename T>
struct ta_util<std_tinf, IsBuiltin, T> {
static inline const std::type_info* get() {
return &(typeid(T));
}
};
template <>
struct ta_util<std_tinf, true, anything> {
static inline const std::type_info* get() {
return nullptr;
}
};
template <class T>
struct ta_util<caf_tinf, true, T> {
static inline const uniform_type_info* get() {
return uniform_typeid(typeid(T));
}
};
template <>
struct ta_util<caf_tinf, true, anything> {
static inline const uniform_type_info* get() {
return nullptr;
}
};
template <class T>
struct ta_util<caf_tinf, false, T> {
static inline const uniform_type_info* get() {
return nullptr;
}
};
// only built-in types are guaranteed to be available at static initialization
// time, other types are announced at runtime
// implements types_array
template <bool BuiltinOnlyTypes, class... T>
struct types_array_impl {
static constexpr bool builtin_only = true;
inline bool is_pure() const { return true; }
// all types are builtin, perform lookup on constuction
const uniform_type_info* data[sizeof...(T) == 0 ? 1 : sizeof...(T)];
types_array_impl() : data{ta_util<caf_tinf, true, T>::get()...} {}
inline const uniform_type_info* operator[](size_t p) const {
return data[p];
}
using const_iterator = const uniform_type_info* const*;
inline const_iterator begin() const { return std::begin(data); }
inline const_iterator end() const { return std::end(data); }
};
template <class... T>
struct types_array_impl<false, T...> {
static constexpr bool builtin_only = false;
inline bool is_pure() const { return false; }
// contains std::type_info for all non-builtin types
const std::type_info* tinfo_data[sizeof...(T) == 0 ? 1 : sizeof...(T)];
// contains uniform_type_infos for builtin types and lazy initializes
// non-builtin types at runtime
mutable std::atomic<const uniform_type_info*> data[sizeof...(T)];
mutable std::atomic<const uniform_type_info**> pairs;
// pairs[sizeof...(T)];
types_array_impl()
: tinfo_data{ta_util<std_tinf, is_builtin<T>::value, T>::get()...} {
bool static_init[sizeof...(T)] = {!std::is_same<T, anything>::value &&
is_builtin<T>::value...};
for (size_t i = 0; i < sizeof...(T); ++i) {
if (static_init[i]) {
data[i].store(uniform_typeid(*(tinfo_data[i])),
std::memory_order_relaxed);
}
}
}
inline const uniform_type_info* operator[](size_t p) const {
auto result = data[p].load();
if (result == nullptr) {
auto tinfo = tinfo_data[p];
if (tinfo != nullptr) {
result = uniform_typeid(*tinfo);
data[p].store(result, std::memory_order_relaxed);
}
}
return result;
}
using const_iterator = const uniform_type_info* const*;
inline const_iterator begin() const {
auto result = pairs.load();
if (result == nullptr) {
auto parr = new const uniform_type_info* [sizeof...(T)];
for (size_t i = 0; i < sizeof...(T); ++i) {
parr[i] = (*this)[i];
}
if (!pairs.compare_exchange_weak(result, parr,
std::memory_order_relaxed)) {
delete[] parr;
} else {
result = parr;
}
}
return result;
}
inline const_iterator end() const { return begin() + sizeof...(T); }
};
// a container for uniform_type_information singletons with optimization
// for builtin types; can act as pattern
template <class... Ts>
struct types_array :
types_array_impl<tl_forall<type_list<Ts...>, is_builtin>::value, Ts...> {
static constexpr size_t size = sizeof...(Ts);
using types = type_list<Ts...>;
using filtered_types = typename tl_filter_not<types, is_anything>::type;
static constexpr size_t filtered_size = tl_size<filtered_types>::value;
inline bool has_values() const { return false; }
};
// utility for singleton-like access to a types_array
template <class... T>
struct static_types_array {
static types_array<T...> arr;
};
template <class... T>
types_array<T...> static_types_array<T...>::arr;
template <class TypeList>
struct static_types_array_from_type_list;
template <class... T>
struct static_types_array_from_type_list<type_list<T...>> {
using type = static_types_array<T...>;
};
template <class... T>
struct static_type_list;
template <class T>
struct static_type_list<T> {
static const std::type_info* list;
static inline const std::type_info* by_offset(size_t offset) {
return offset == 0 ? list : &typeid(type_list<>);
}
};
template <class T>
const std::type_info* static_type_list<T>::list = &typeid(type_list<T>);
// utility for singleton-like access to a type_info instance of a type_list
template <class T0, typename T1, class... Ts>
struct static_type_list<T0, T1, Ts...> {
static const std::type_info* list;
static inline const std::type_info* by_offset(size_t offset) {
return offset == 0 ? list : static_type_list<T1, Ts...>::list;
}
};
template <class T0, typename T1, class... Ts>
const std::type_info* static_type_list<T0, T1, Ts...>::list =
&typeid(type_list<T0, T1, Ts...>);
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_TYPES_ARRAY_HPP
......@@ -69,11 +69,13 @@ class uniform_type_info_map {
virtual pointer by_uniform_name(const std::string& name) = 0;
virtual pointer by_type_nr(uint16_t) const = 0;
virtual pointer by_rtti(const std::type_info& ti) const = 0;
virtual std::vector<pointer> get_all() const = 0;
virtual pointer insert(uniform_type_info_ptr uti) = 0;
virtual pointer insert(const std::type_info*, uniform_type_info_ptr) = 0;
static uniform_type_info_map* create_singleton();
......
......@@ -33,6 +33,7 @@ class group;
class message;
class channel;
class node_id;
class duration;
class behavior;
class resumable;
class actor_addr;
......@@ -50,8 +51,15 @@ class event_based_actor;
class forwarding_actor_proxy;
// structs
struct unit_t;
struct anything;
struct exit_msg;
struct down_msg;
struct timeout_msg;
struct group_down_msg;
struct invalid_actor_t;
struct sync_exited_msg;
struct sync_timeout_msg;
struct invalid_actor_addr_t;
struct illegal_message_element;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_MATCH_HPP
#define CAF_MATCH_HPP
#include <vector>
#include <istream>
#include <iterator>
#include <type_traits>
#include "caf/message.hpp"
#include "caf/match_expr.hpp"
#include "caf/skip_message.hpp"
#include "caf/message_handler.hpp"
#include "caf/message_builder.hpp"
#include "caf/detail/tbind.hpp"
#include "caf/detail/type_list.hpp"
namespace caf {
namespace detail {
class match_helper {
match_helper(const match_helper&) = delete;
match_helper& operator=(const match_helper&) = delete;
public:
match_helper(match_helper&&) = default;
inline match_helper(message t) : tup(std::move(t)) { }
template <class... Ts>
auto operator()(Ts&&... args)
-> decltype(match_expr_collect(std::forward<Ts>(args)...)(message{})) {
static_assert(sizeof...(Ts) > 0, "at least one argument required");
auto tmp = match_expr_collect(std::forward<Ts>(args)...);
return tmp(tup);
}
private:
message tup;
};
template <class T, typename InputIterator>
class stream_matcher {
public:
using iterator = InputIterator;
stream_matcher(iterator first, iterator last) : m_pos(first), m_end(last) {
// nop
}
template <class... Ts>
bool operator()(Ts&&... args) {
auto mexpr = match_expr_collect(std::forward<Ts>(args)...);
//TODO: static_assert -> mexpr must not have a wildcard
constexpr size_t max_handler_args = 0; // TODO: get from mexpr
message_handler handler = mexpr;
while (m_pos != m_end) {
m_mb.append(*m_pos++);
if (m_mb.apply(handler)) {
m_mb.clear();
} else if (m_mb.size() == max_handler_args) {
return false;
}
}
// we have a match if all elements were consumed
return m_mb.empty();
}
private:
iterator m_pos;
iterator m_end;
message_builder m_mb;
};
struct identity_fun {
template <class T>
inline T& operator()(T& arg) { return arg; }
};
template <class InputIterator, typename Transformation = identity_fun>
class match_each_helper {
public:
using iterator = InputIterator;
match_each_helper(iterator first, iterator last, Transformation fun)
: m_pos(first), m_end(last), m_fun(std::move(fun)) {
// nop
}
template <class... Ts>
bool operator()(Ts&&... args) {
message_handler handler = match_expr_collect(std::forward<Ts>(args)...);
for ( ; m_pos != m_end; ++m_pos) {
if (!handler(m_fun(*m_pos))) return false;
}
return true;
}
private:
iterator m_pos;
iterator m_end;
Transformation m_fun;
};
} // namespace detail
} // namespace caf
namespace caf {
/**
* Starts a match expression.
* @param what Tuple that should be matched against a pattern.
* @returns A helper object providing `operator(...).
*/
inline detail::match_helper match(message what) {
return what;
}
/**
* Starts a match expression.
* @param what Value that should be matched against a pattern.
* @returns A helper object providing `operator(...).
*/
template <class T>
detail::match_helper match(T&& what) {
return message_builder{}.append(std::forward<T>(what)).to_message();
}
/**
* Splits `str` using `delim` and match the resulting strings.
*/
detail::match_helper
match_split(const std::string& str, char delim, bool keep_empties = false);
/**
* Starts a match expression that matches each element in
* range [first, last).
* @param first Iterator to the first element.
* @param last Iterator to the last element (excluded).
* @returns A helper object providing `operator(...).
*/
template <class InputIterator>
detail::match_each_helper<InputIterator>
match_each(InputIterator first, InputIterator last) {
return {first, last, detail::identity_fun{}};
}
/**
* Starts a match expression that matches `proj(i) for
* each element `i` in range [first, last).
* @param first Iterator to the first element.
* @param last Iterator to the last element (excluded).
* @param proj Projection or extractor functor.
* @returns A helper object providing `operator(...).
*/
template <class InputIterator, typename Projection>
detail::match_each_helper<InputIterator, Projection>
match_each(InputIterator first, InputIterator last, Projection proj) {
return {first, last, std::move(proj)};
}
template <class T>
detail::stream_matcher<T, std::istream_iterator<T>>
match_stream(std::istream& stream) {
std::istream_iterator<T> first(stream);
std::istream_iterator<T> last; // 'end of stream' iterator
return {first, last};
}
template <class T, typename InputIterator>
detail::stream_matcher<T, InputIterator>
match_stream(InputIterator first, InputIterator last) {
return {first, last};
}
} // namespace caf
#endif // CAF_MATCH_HPP
......@@ -71,14 +71,20 @@ class match_expr_case : public get_lifted_fun<Expr, Projecs, Signature>::type {
using pattern = Pattern;
using filtered_pattern =
typename detail::tl_filter_not_type<
Pattern,
anything
>::type;
Pattern,
anything
>::type;
static constexpr bool has_wildcard =
!std::is_same<
pattern,
filtered_pattern
>::value;
static constexpr uint32_t type_token = make_type_token_from_list<pattern>();
using intermediate_tuple =
typename detail::tl_apply<
filtered_pattern,
detail::pseudo_tuple
>::type;
typename detail::tl_apply<
filtered_pattern,
detail::pseudo_tuple
>::type;
};
template <class Expr, class Transformers, class Pattern>
......@@ -208,28 +214,25 @@ T& unroll_expr_result_unbox(optional<T>& opt) {
}
template <class Result, class PPFPs, class Msg>
Result unroll_expr(PPFPs&, uint64_t, minus1l, Msg&) {
Result unroll_expr(PPFPs&, minus1l, Msg&) {
// end of recursion
return none;
}
template <class Result, class PPFPs, long N, class Msg>
Result unroll_expr(PPFPs& fs, uint64_t bitmask, long_constant<N>, Msg& msg) {
Result unroll_expr(PPFPs& fs, long_constant<N>, Msg& msg) {
{ // recursively evaluate sub expressions
Result res = unroll_expr<Result>(fs, bitmask, long_constant<N - 1>{}, msg);
Result res = unroll_expr<Result>(fs, long_constant<N - 1>{}, msg);
if (!get<none_t>(&res)) {
return res;
}
}
if ((bitmask & (0x01 << N)) == 0) {
// case is disabled via bitmask
return none;
}
auto& f = get<N>(fs);
using ft = typename std::decay<decltype(f)>::type;
meta_elements<typename ft::pattern> ms;
typename ft::intermediate_tuple targs;
if (try_match(msg, ms.arr.data(), ms.arr.size(), targs.data)) {
if ((ft::has_wildcard || ft::type_token == msg.type_token())
&& try_match(msg, ms.arr.data(), ms.arr.size(), targs.data)) {
auto is = detail::get_indices(targs);
auto res = detail::apply_args(f, is, deduce_const(msg, targs));
if (unroll_expr_result_valid(res)) {
......@@ -239,23 +242,6 @@ Result unroll_expr(PPFPs& fs, uint64_t bitmask, long_constant<N>, Msg& msg) {
return none;
}
template <class PPFPs>
uint64_t calc_bitmask(PPFPs&, minus1l, const std::type_info&, const message&) {
return 0x00;
}
template <class Case, long N>
uint64_t calc_bitmask(Case& fs, long_constant<N>,
const std::type_info& tinf, const message& msg) {
auto& f = get<N>(fs);
using ft = typename std::decay<decltype(f)>::type;
meta_elements<typename ft::pattern> ms;
uint64_t result = try_match(msg, ms.arr.data(), ms.arr.size(), nullptr)
? (0x01 << N)
: 0x00;
return result | calc_bitmask(fs, long_constant<N - 1l>(), tinf, msg);
}
template <bool IsManipulator, typename T0, typename T1>
struct mexpr_fwd_ {
using type = T1;
......@@ -364,16 +350,12 @@ class match_expr {
template <class T, class... Ts>
match_expr(T v, Ts&&... vs) : m_cases(std::move(v), std::forward<Ts>(vs)...) {
init();
// nop
}
match_expr(match_expr&& other) : m_cases(std::move(other.m_cases)) {
init();
}
match_expr(match_expr&&) = default;
match_expr(const match_expr& other) : m_cases(other.m_cases) {
init();
}
match_expr(const match_expr&) = default;
result_type operator()(const message& tup) {
return apply(tup);
......@@ -418,58 +400,6 @@ class match_expr {
using cache_element = std::pair<const std::type_info*, uint64_t>;
std::vector<cache_element> m_cache;
// ring buffer like access to m_cache
size_t m_cache_begin;
size_t m_cache_end;
cache_element m_dummy;
static void advance_(size_t& i) {
i = (i + 1) % cache_size;
}
size_t find_token_pos(const std::type_info* type_token) {
for (size_t i = m_cache_begin; i != m_cache_end; advance_(i)) {
if (m_cache[i].first == type_token) {
return i;
}
}
return m_cache_end;
}
template <class Tuple>
uint64_t get_cache_entry(const std::type_info* type_token,
const Tuple& value) {
CAF_REQUIRE(type_token != nullptr);
if (value.dynamically_typed()) {
return m_dummy.second; // all groups enabled
}
size_t i = find_token_pos(type_token);
// if we didn't found a cache entry ...
if (i == m_cache_end) {
// ... 'create' one (override oldest element in cache if full)
advance_(m_cache_end);
if (m_cache_end == m_cache_begin) {
advance_(m_cache_begin);
}
m_cache[i].first = type_token;
idx_token_type idx_token;
m_cache[i].second = calc_bitmask(m_cases, idx_token, *type_token, value);
}
return m_cache[i].second;
}
void init() {
m_dummy.second = std::numeric_limits<uint64_t>::max();
m_cache.resize(cache_size);
for (auto& entry : m_cache) {
entry.first = nullptr;
}
m_cache_begin = m_cache_end = 0;
}
template <class Msg>
result_type apply(Msg& msg) {
idx_token_type idx_token;
......@@ -477,8 +407,7 @@ class match_expr {
// returns either a reference or a new object
using detached = decltype(detail::detach_if_needed(msg, mutator_token));
detached mref = detail::detach_if_needed(msg, mutator_token);
auto bitmask = get_cache_entry(mref.type_token(), mref);
return detail::unroll_expr<result_type>(m_cases, bitmask, idx_token, mref);
return detail::unroll_expr<result_type>(m_cases, idx_token, mref);
}
};
......
......@@ -20,10 +20,13 @@
#ifndef CAF_MESSAGE_HPP
#define CAF_MESSAGE_HPP
#include <tuple>
#include <type_traits>
#include "caf/atom.hpp"
#include "caf/config.hpp"
#include "caf/from_string.hpp"
#include "caf/skip_message.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/comparable.hpp"
......@@ -55,11 +58,6 @@ class message {
*/
using data_ptr = detail::message_data::ptr;
/**
* An iterator to access each element as `const void*.
*/
using const_iterator = detail::message_data::const_iterator;
/**
* Creates an empty tuple.
*/
......@@ -93,29 +91,34 @@ class message {
}
/**
* Creates a new tuple with all but the first n values.
* Creates a new message with all but the first n values.
*/
message drop(size_t n) const;
/**
* Creates a new tuple with all but the last n values.
* Creates a new message with all but the last n values.
*/
message drop_right(size_t n) const;
/**
* Creates a new tuple from the first n values.
* Creates a new message from the first n values.
*/
inline message take(size_t n) const {
return n >= size() ? *this : drop_right(size() - n);
}
/**
* Creates a new tuple from the last n values.
* Creates a new message from the last n values.
*/
inline message take_right(size_t n) const {
return n >= size() ? *this : drop(size() - n);
}
/**
* Creates a new message of size `n` starting at element `pos`.
*/
message slice(size_t pos, size_t n) const;
/**
* Gets a mutable pointer to the element at position @p p.
*/
......@@ -126,28 +129,7 @@ class message {
*/
const void* at(size_t p) const;
/**
* Gets {@link uniform_type_info uniform type information}
* of the element at position @p p.
*/
const uniform_type_info* type_at(size_t p) const;
/**
* Returns true if this message has the types @p Ts.
*/
template <class... Ts>
bool has_types() const {
if (size() != sizeof...(Ts)) {
return false;
}
const std::type_info* ts[] = {&typeid(Ts)...};
for (size_t i = 0; i < sizeof...(Ts); ++i) {
if (!type_at(i)->equal_to(*ts[i])) {
return false;
}
}
return true;
}
const char* uniform_name_at(size_t pos) const;
/**
* Returns @c true if `*this == other, otherwise false.
......@@ -166,7 +148,7 @@ class message {
*/
template <class T>
inline const T& get_as(size_t p) const {
CAF_REQUIRE(*(type_at(p)) == typeid(T));
CAF_REQUIRE(match_element(p, detail::type_nr<T>::value, &typeid(T)));
return *reinterpret_cast<const T*>(at(p));
}
......@@ -175,20 +157,10 @@ class message {
*/
template <class T>
inline T& get_as_mutable(size_t p) {
CAF_REQUIRE(*(type_at(p)) == typeid(T));
CAF_REQUIRE(match_element(p, detail::type_nr<T>::value, &typeid(T)));
return *reinterpret_cast<T*>(mutable_at(p));
}
/**
* Returns an iterator to the beginning.
*/
const_iterator begin() const;
/**
* Returns an iterator to the end.
*/
const_iterator end() const;
/**
* Returns a copy-on-write pointer to the internal data.
*/
......@@ -211,28 +183,117 @@ class message {
}
/**
* Returns either `&typeid(detail::type_list<Ts...>)`, where
* `Ts...` are the element types, or `&typeid(void)`.
*
* The type token `&typeid(void)` indicates that this tuple is dynamically
* typed, i.e., the types where not available at compile time.
*/
const std::type_info* type_token() const;
/**
* Checks whether this tuple is dynamically typed, i.e.,
* Checks whether this message is dynamically typed, i.e.,
* its types were not known at compile time.
*/
bool dynamically_typed() const;
/**
* Applies @p handler to this message and returns the result
* Applies `handler` to this message and returns the result
* of `handler(*this)`.
*/
optional<message> apply(message_handler handler);
/**
* Returns a new message consisting of all elements that were *not*
* matched by `handler`.
*/
message filter(message_handler handler) const;
/**
* Stores the name of a command line option ("<long name>[,<short name>]")
* along with a description and a callback.
*/
struct cli_arg {
std::string name;
std::string text;
std::function<bool (const std::string&)> fun;
inline cli_arg(std::string nstr, std::string tstr)
: name(std::move(nstr)),
text(std::move(tstr)) {
// nop
}
inline cli_arg(std::string nstr, std::string tstr, std::string& arg)
: name(std::move(nstr)),
text(std::move(tstr)) {
fun = [&arg](const std::string& str) -> bool{
arg = str;
return true;
};
}
inline cli_arg(std::string nstr, std::string tstr, std::vector<std::string>& arg)
: name(std::move(nstr)),
text(std::move(tstr)) {
fun = [&arg](const std::string& str) -> bool {
arg.push_back(str);
return true;
};
}
template <class T>
cli_arg(std::string nstr, std::string tstr, T& arg)
: name(std::move(nstr)),
text(std::move(tstr)) {
fun = [&arg](const std::string& str) -> bool {
auto res = from_string<T>(str);
if (!res) {
return false;
}
arg = *res;
return true;
};
}
template <class T>
cli_arg(std::string nstr, std::string tstr, std::vector<T>& arg)
: name(std::move(nstr)),
text(std::move(tstr)) {
fun = [&arg](const std::string& str) -> bool {
auto res = from_string<T>(str);
if (!res) {
return false;
}
arg.push_back(*res);
return true;
};
}
};
struct cli_res;
/**
* A simplistic interface for using `filter` to parse command line options.
*/
cli_res filter_cli(std::vector<cli_arg> args) const;
/**
* Queries whether the element at `pos` is of type `T`.
* @param pos Index of element in question.
*/
template <class T>
bool match_element(size_t pos) const {
const std::type_info* rtti = nullptr;
if (detail::type_nr<T>::value == 0) {
rtti = &typeid(T);
}
return match_element(pos, detail::type_nr<T>::value, rtti);
}
/**
* Queries whether the types of this message are `Ts...`.
*/
template <class... Ts>
bool match_elements() const {
std::integral_constant<size_t, 0> p0;
detail::type_list<Ts...> tlist;
return size() == sizeof...(Ts) && match_elements_impl(p0, tlist);
}
/** @cond PRIVATE */
inline uint32_t type_token() const {
return m_vals ? m_vals->type_token() : 0xFFFFFFFF;
}
inline void force_detach() {
m_vals.detach();
}
......@@ -241,7 +302,7 @@ class message {
explicit message(raw_ptr);
inline const std::string* tuple_type_names() const {
inline std::string tuple_type_names() const {
return m_vals->tuple_type_names();
}
......@@ -260,12 +321,57 @@ class message {
return detail::apply_args(f, detail::get_indices(tup), tup);
}
/**
* Tries to match element at position `pos` to given RTTI.
* @param pos Index of element in question.
* @param typenr Number of queried type or `0` for custom types.
* @param rtti Queried type or `nullptr` for builtin types.
*/
bool match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const;
template <class T, class... Ts>
bool match_elements(detail::type_list<T, Ts...> list) const {
std::integral_constant<size_t, 0> p0;
return size() == (sizeof...(Ts) + 1) && match_elements_impl(p0, list);
}
/** @endcond */
private:
template <size_t P>
bool match_elements_impl(std::integral_constant<size_t, P>,
detail::type_list<>) const {
return true; // end of recursion
}
template <size_t P, class T, class... Ts>
bool match_elements_impl(std::integral_constant<size_t, P>,
detail::type_list<T, Ts...>) const {
std::integral_constant<size_t, P + 1> next_p;
detail::type_list<Ts...> next_list;
return match_element<T>(P)
&& match_elements_impl(next_p, next_list);
}
message filter_impl(size_t start, message_handler handler) const;
data_ptr m_vals;
};
/**
* Stores the result of `message::filter_cli`.
*/
struct message::cli_res {
/**
* Stores the remaining (unmatched) arguments.
*/
message remainder;
/**
* Stores the names of all active options.
*/
std::set<std::string> opts;
/**
* Stores the automatically generated help text.
*/
std::string helptext;
};
/**
......
......@@ -90,6 +90,14 @@ class message_builder {
*/
message to_message();
inline message filter(message_handler f) {
return to_message().filter(f);
}
inline message::cli_res filter_cli(std::vector<message::cli_arg> args) {
return to_message().filter_cli(std::move(args));
}
/**
* Convenience function for `to_message().apply(handler).
*/
......@@ -117,7 +125,9 @@ class message_builder {
template <class T>
message_builder&
append_impl(typename detail::implicit_conversions<T>::type what) {
append_impl(typename unbox_message_element<
typename detail::implicit_conversions<T>::type
>::type what) {
using type = decltype(what);
auto uti = uniform_typeid<type>();
auto uval = uti->create();
......
......@@ -162,8 +162,7 @@ struct rvalue_builder {
rvalue_builder(fun_container arg1) : m_funs(std::move(arg1)) {}
template <class Expr>
match_expr<
typename get_case<is_complete, Expr, Transformers, Pattern>::type>
match_expr<typename get_case<is_complete, Expr, Transformers, Pattern>::type>
operator>>(Expr expr) const {
using lifted_expr =
typename get_case<
......@@ -177,10 +176,16 @@ struct rvalue_builder {
using trimmed_projections = typename tl_trim<Transformers>::type;
tuple_maker f;
auto lhs = apply_args(f, get_indices(trimmed_projections{}), m_funs);
typename tl_apply<
typename tl_slice<target, tl_size<trimmed_projections>::value,
tl_size<target>::value>::type,
std::tuple>::type rhs;
using rhs_type =
typename tl_apply<
typename tl_slice<
target,
tl_size<trimmed_projections>::value,
tl_size<target>::value
>::type,
std::tuple
>::type;
rhs_type rhs;
// done
return lifted_expr{std::move(expr), std::tuple_cat(lhs, rhs)};
}
......@@ -216,9 +221,18 @@ struct pattern_type_<false, T> {
};
template <class T>
struct pattern_type
: pattern_type_<
detail::is_callable<T>::value && !detail::is_boxed<T>::value, T> { };
struct pattern_type {
using type =
typename pattern_type_<
detail::is_callable<T>::value && !detail::is_boxed<T>::value,
T
>::type;
};
template <atom_value V>
struct pattern_type<atom_constant<V>> {
using type = atom_value;
};
} // namespace detail
} // namespace caf
......@@ -302,11 +316,12 @@ constexpr boxed_arg_match_t arg_match = boxed_arg_match_t();
template <class T, typename Predicate>
std::function<optional<T>(const T&)> guarded(Predicate p, T value) {
return[=](const T & other)->optional<T> {
if (p(other, value)) return value;
return none;
};
return [=](const T& other) -> optional<T> {
if (p(other, value)) {
return value;
}
return none;
};
}
// special case covering arg_match as argument to guarded()
......@@ -344,6 +359,11 @@ F to_guard(F fun,
return fun;
}
template <atom_value V>
auto to_guard(const atom_constant<V>&) -> decltype(to_guard(V)) {
return to_guard(V);
}
template <class T, class... Ts>
auto on(const T& arg, const Ts&... args)
-> detail::rvalue_builder<
......
......@@ -147,7 +147,9 @@ class invoke_policy {
}
} else {
CAF_LOGF_DEBUG("res = " << to_string(*res));
if (res->template has_types<atom_value, uint64_t>()
if (res->size() == 2
&& res->match_element(0, detail::type_nr<atom_value>::value, nullptr)
&& res->match_element(1, detail::type_nr<uint64_t>::value, nullptr)
&& res->template get_as<atom_value>(0) == atom("MESSAGE_ID")) {
CAF_LOG_DEBUG("message handler returned a message id wrapper");
auto id = res->template get_as<uint64_t>(1);
......@@ -287,7 +289,7 @@ class invoke_policy {
const message& msg = node->msg;
auto mid = node->mid;
if (msg.size() == 1) {
if (msg.type_at(0)->equal_to(typeid(exit_msg))) {
if (msg.match_element<exit_msg>(0)) {
auto& em = msg.get_as<exit_msg>(0);
CAF_REQUIRE(!mid.valid());
// make sure to get rid of attachables if they're no longer needed
......@@ -299,7 +301,7 @@ class invoke_policy {
}
return msg_type::normal_exit;
}
} else if (msg.type_at(0)->equal_to(typeid(timeout_msg))) {
} else if (msg.match_element<timeout_msg>(0)) {
auto& tm = msg.get_as<timeout_msg>(0);
auto tid = tm.timeout_id;
CAF_REQUIRE(!mid.valid());
......@@ -308,8 +310,7 @@ class invoke_policy {
}
return self->waits_for_timeout(tid) ? msg_type::inactive_timeout
: msg_type::expired_timeout;
} else if (msg.type_at(0)->equal_to(typeid(sync_timeout_msg))
&& mid.is_response()) {
} else if (mid.is_response() && msg.match_element<sync_timeout_msg>(0)) {
return msg_type::timeout_response;
}
}
......
......@@ -33,28 +33,26 @@ namespace policy {
* An actor that is scheduled or otherwise managed.
*/
class sequential_invoke : public invoke_policy<sequential_invoke> {
public:
inline bool hm_should_skip(mailbox_element*) { return false; }
inline bool hm_should_skip(mailbox_element*) {
return false;
}
template <class Actor>
inline mailbox_element* hm_begin(Actor* self, mailbox_element* node) {
auto previous = self->current_node();
mailbox_element* hm_begin(Actor* self, mailbox_element* node) {
self->current_node(node);
return previous;
return nullptr;
}
template <class Actor>
inline void hm_cleanup(Actor* self, mailbox_element*) {
void hm_cleanup(Actor* self, mailbox_element*) {
self->current_node(self->dummy_node());
}
template <class Actor>
inline void hm_revert(Actor* self, mailbox_element* previous) {
self->current_node(previous);
void hm_revert(Actor* self, mailbox_element*) {
self->current_node(self->dummy_node());
}
};
} // namespace policy
......
......@@ -23,7 +23,6 @@
#include <string>
#include "caf/either.hpp"
#include "caf/uniform_typeid.hpp"
#include "caf/type_name_access.hpp"
#include "caf/uniform_type_info.hpp"
#include "caf/illegal_message_element.hpp"
......
......@@ -72,7 +72,7 @@ template <class T>
optional<T> from_string(const std::string& what) {
auto uti = uniform_typeid<T>();
auto uv = from_string_impl(what);
if (!uv || (*uv->ti) != typeid(T)) {
if (!uv || uv->ti != uti) {
// try again using the type name
std::string tmp = uti->name();
tmp += " ( ";
......@@ -80,7 +80,7 @@ optional<T> from_string(const std::string& what) {
tmp += " )";
uv = from_string_impl(tmp);
}
if (uv && (*uv->ti) == typeid(T)) {
if (uv && uv->ti == uti) {
return T{std::move(*reinterpret_cast<T*>(uv->val))};
}
return none;
......
......@@ -158,9 +158,9 @@ uniform_value make_uniform_value(const uniform_type_info* ti, Ts&&... args) {
* \@_::foo
*/
class uniform_type_info {
public:
friend bool operator==(const uniform_type_info& lhs,
const uniform_type_info& rhs);
const uniform_type_info& rhs);
// disable copy and move constructors
uniform_type_info(uniform_type_info&&) = delete;
......@@ -170,8 +170,6 @@ class uniform_type_info {
uniform_type_info& operator=(uniform_type_info&&) = delete;
uniform_type_info& operator=(const uniform_type_info&) = delete;
public:
virtual ~uniform_type_info();
/**
......@@ -254,9 +252,15 @@ class uniform_type_info {
*/
virtual message as_message(void* instance) const = 0;
protected:
/**
* Returns a unique number for builtin types or 0.
*/
uint16_t type_nr() const {
return m_type_nr;
}
uniform_type_info() = default;
protected:
uniform_type_info(uint16_t typenr = 0);
template <class T>
uniform_value create_impl(const uniform_value& other) const {
......@@ -268,6 +272,8 @@ class uniform_type_info {
return make_uniform_value<T>(this);
}
private:
uint16_t m_type_nr;
};
using uniform_type_info_ptr = std::unique_ptr<uniform_type_info>;
......@@ -294,38 +300,6 @@ inline bool operator!=(const uniform_type_info& lhs,
return !(lhs == rhs);
}
/**
* @relates uniform_type_info
*/
inline bool operator==(const uniform_type_info& lhs,
const std::type_info& rhs) {
return lhs.equal_to(rhs);
}
/**
* @relates uniform_type_info
*/
inline bool operator!=(const uniform_type_info& lhs,
const std::type_info& rhs) {
return !(lhs.equal_to(rhs));
}
/**
* @relates uniform_type_info
*/
inline bool operator==(const std::type_info& lhs,
const uniform_type_info& rhs) {
return rhs.equal_to(lhs);
}
/**
* @relates uniform_type_info
*/
inline bool operator!=(const std::type_info& lhs,
const uniform_type_info& rhs) {
return !(rhs.equal_to(lhs));
}
} // namespace caf
#endif // CAF_UNIFORM_TYPE_INFO_HPP
......@@ -22,16 +22,36 @@
#include <typeinfo>
#include "caf/detail/type_nr.hpp"
namespace caf {
class uniform_type_info;
/**
* Returns the uniform type info for the builtin type identified by `nr`.
* @pre `nr > 0 && nr < detail::type_nrs`
*/
const uniform_type_info* uniform_typeid_by_nr(uint16_t nr);
/**
* Returns the uniform type info for type `tinf`.
* @param allow_nullptr if set to true, this function returns `nullptr` instead
* of throwing an exception on error
*/
const uniform_type_info* uniform_typeid(const std::type_info& tinf,
bool allow_nullptr = false);
/**
* Returns the uniform type info for type `T`.
* @param allow_nullptr if set to true, this function returns `nullptr` instead
* of throwing an exception on error
*/
template <class T>
const uniform_type_info* uniform_typeid(bool allow_nullptr = false) {
return uniform_typeid(typeid(T), allow_nullptr);
auto nr = detail::type_nr<T>::value;
return (nr != 0) ? uniform_typeid_by_nr(nr)
: uniform_typeid(typeid(T), allow_nullptr);
}
} // namespace caf
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CPPA_COW_TUPLE_HPP
#define CPPA_COW_TUPLE_HPP
// <backward_compatibility version="0.9" whole_file="yes">
#include <cstddef>
#include <string>
#include <typeinfo>
#include <type_traits>
#include "caf/message.hpp"
#include "caf/ref_counted.hpp"
#include "caf/detail/tuple_vals.hpp"
#include "caf/detail/decorated_tuple.hpp"
#include "caf/detail/implicit_conversions.hpp"
namespace caf {
template <class... Ts>
class cow_tuple;
template <class Head, class... Tail>
class cow_tuple<Head, Tail...> {
static_assert(detail::tl_forall<detail::type_list<Head, Tail...>,
detail::is_legal_tuple_type
>::value,
"illegal types in cow_tuple definition: "
"pointers and references are prohibited");
using data_type =
detail::tuple_vals<typename detail::strip_and_convert<Head>::type,
typename detail::strip_and_convert<Tail>::type...>;
using data_ptr = detail::message_data::ptr;
public:
using types = detail::type_list<Head, Tail...>;
static constexpr size_t num_elements = sizeof...(Tail) + 1;
cow_tuple() : m_vals(new data_type) {
// nop
}
template <class... Ts>
cow_tuple(Head arg, Ts&&... args)
: m_vals(new data_type(std::move(arg), std::forward<Ts>(args)...)) {
// nop
}
cow_tuple(cow_tuple&&) = default;
cow_tuple(const cow_tuple&) = default;
cow_tuple& operator=(cow_tuple&&) = default;
cow_tuple& operator=(const cow_tuple&) = default;
inline size_t size() const {
return sizeof...(Tail) + 1;
}
inline const void* at(size_t p) const {
return m_vals->at(p);
}
inline void* mutable_at(size_t p) {
return m_vals->mutable_at(p);
}
inline const uniform_type_info* type_at(size_t p) const {
return m_vals->type_at(p);
}
inline cow_tuple<Tail...> drop_left() const {
return cow_tuple<Tail...>::offset_subtuple(m_vals, 1);
}
inline operator message() const {
return message{m_vals};
}
static cow_tuple from(message& msg) {
return cow_tuple(msg.vals());
}
private:
cow_tuple(data_ptr ptr) : m_vals(ptr) { }
data_type* ptr() {
return static_cast<data_type*>(m_vals.get());
}
const data_type* ptr() const {
return static_cast<data_type*>(m_vals.get());
}
data_ptr m_vals;
};
template <size_t N, class... Ts>
const typename detail::type_at<N, Ts...>::type&
get(const cow_tuple<Ts...>& tup) {
using result_type = typename detail::type_at<N, Ts...>::type;
return *reinterpret_cast<const result_type*>(tup.at(N));
}
template <size_t N, class... Ts>
typename detail::type_at<N, Ts...>::type&
get_ref(cow_tuple<Ts...>& tup) {
using result_type = typename detail::type_at<N, Ts...>::type;
return *reinterpret_cast<result_type*>(tup.mutable_at(N));
}
template <class... Ts>
cow_tuple<typename detail::strip_and_convert<Ts>::type...>
make_cow_tuple(Ts&&... args) {
return {std::forward<Ts>(args)...};
}
template <class TypeList>
struct cow_tuple_from_type_list;
template <class... Ts>
struct cow_tuple_from_type_list<detail::type_list<Ts...>> {
typedef cow_tuple<Ts...> type;
};
} // namespace caf
// </backward_compatibility>
#endif // CPPA_COW_TUPLE_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CPPA_CPPA_HPP
#define CPPA_CPPA_HPP
// <backward_compatibility version="0.9" whole_file="yes">
// include new header
#include "caf/all.hpp"
// include compatibility headers
#include "cppa/opt.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/cow_tuple.hpp"
#include "cppa/tuple_cast.hpp"
#include "cppa/publish_local_groups.hpp"
// headers for classes and functions that have been moved
#include "caf/io/all.hpp"
// be nice to code using legacy macros
#define CPPA_VERSION CAF_VERSION
// set old namespace to new namespace
namespace cppa = caf;
// re-import a couple of moved things backinto the global CAF namespace
namespace caf {
using io::accept_handle;
using io::connection_handle;
using io::publish;
using io::remote_actor;
using io::max_msg_size;
using io::typed_publish;
using io::typed_remote_actor;
using io::publish_local_groups;
using io::new_connection_msg;
using io::new_data_msg;
using io::connection_closed_msg;
using io::acceptor_closed_msg;
} // namespace caf
// </backward_compatibility>
#endif // CPPA_CPPA_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CPPA_CPPA_FWD_HPP
#define CPPA_CPPA_FWD_HPP
// <backward_compatibility version="0.9" whole_file="yes">
#include "caf/fwd.hpp"
namespace caf {
using any_tuple = message;
template <class... Ts>
class cow_tuple;
} // namespace caf
// </backward_compatibility>
#endif // CPPA_CPPA_FWD_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CPPA_OPT_HPP
#define CPPA_OPT_HPP
// <backward_compatibility version="0.9" whole_file="yes">
#include <map>
#include <string>
#include <vector>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <functional>
#include "caf/on.hpp"
#include "caf/optional.hpp"
#include "cppa/opt_impls.hpp"
namespace caf {
using string_proj = std::function<optional<std::string> (const std::string&)>;
inline string_proj extract_longopt_arg(const std::string& prefix) {
return [prefix](const std::string& arg) -> optional<std::string> {
if (arg.compare(0, prefix.size(), prefix) == 0) {
return std::string(arg.begin() + static_cast<ptrdiff_t>(prefix.size()),
arg.end());
}
return none;
};
}
/**
* Right-hand side of a match expression for a program option
* reading an argument of type `T`.
*/
template <class T>
detail::rd_arg_functor<T> rd_arg(T& storage) {
return {storage};
}
/**
* Right-hand side of a match expression for a program option
* adding an argument of type `T` to `storage`.
*/
template <class T>
detail::add_arg_functor<T> add_arg(std::vector<T>& storage) {
return {storage};
}
/**
* Right-hand side of a match expression for a program option
* reading a boolean flag.
*/
inline std::function<void()> set_flag(bool& storage) {
return [&] { storage = true; };
}
/**
* Stores a help text along with the number of expected arguments.
*/
struct option_info {
std::string help_text;
size_t num_args;
};
/**
* Stores a help text for program options with option groups.
*/
using options_description =
std::map<
std::string,
std::map<
std::pair<char, std::string>,
option_info
>
>;
using opt_rvalue_builder =
decltype(on(std::function<optional<std::string> (const std::string&)>{})
|| on(std::string{}, val<std::string>));
using opt0_rvalue_builder = decltype(on(std::string{}) || on(std::string{}));
/**
* Left-hand side of a match expression for a program option with one argument.
*/
inline opt_rvalue_builder on_opt1(char short_opt,
std::string long_opt,
options_description* desc = nullptr,
std::string help_text = "",
std::string help_group = "general options") {
if (desc) {
option_info oinf{move(help_text), 1};
(*desc)[help_group].insert(std::make_pair(
std::make_pair(short_opt, long_opt),
std::move(oinf)));
}
const char short_flag_arr[] = {'-', short_opt, '\0' };
const char* lhs_str = short_flag_arr;
std::string prefix = "--";
prefix += std::move(long_opt);
prefix += "=";
return on(extract_longopt_arg(prefix)) || on(lhs_str, val<std::string>);
}
/**
* Left-hand side of a match expression for a program option with no argument.
*/
inline opt0_rvalue_builder on_opt0(char short_opt,
std::string long_opt,
options_description* desc = nullptr,
std::string help_text = "",
std::string help_group = "general options") {
if (desc) {
option_info oinf{help_text, 0};
(*desc)[help_group].insert(std::make_pair(std::make_pair(short_opt,
long_opt),
std::move(oinf)));
}
const char short_flag_arr[] = {'-', short_opt, '\0' };
std::string short_opt_string = short_flag_arr;
return on("--" + long_opt) || on(short_opt_string);
}
/**
* Returns a function that prints the help text of `desc` to `out`.
*/
inline std::function<void()> print_desc(options_description* desc,
std::ostream& out = std::cout) {
return [&out, desc] {
if (!desc) return;
if (desc->empty()) {
out << "please use '-h' or '--help' for a list "
"of available program options\n";
}
for (auto& opt_group : *desc) {
out << opt_group.first << ":\n";
for (auto& opt : opt_group.second) {
out << " ";
out << std::setw(40) << std::left;
std::ostringstream tmp;
auto& names = opt.first;
if (names.first != '\0') {
tmp << "-" << names.first;
for (size_t num = 1; num <= opt.second.num_args; ++num) {
tmp << " <arg" << num << ">";
}
tmp << " | ";
}
tmp << "--" << names.second;
if (opt.second.num_args > 0) {
tmp << "=<arg1>";
}
for (size_t num = 2; num <= opt.second.num_args; ++num) {
tmp << ", <arg" << num << ">";
}
out << tmp.str() << opt.second.help_text << "\n";
}
out << "\n";
}
};
}
/**
* Returns a function that prints the help text of `desc` to `out`
* and then calls `exit(exit_reason).
*/
inline std::function<void()> print_desc_and_exit(options_description* desc,
std::ostream& out = std::cout,
int exit_reason = 0) {
auto fun = print_desc(desc, out);
return [=] {
fun();
exit(exit_reason);
};
}
} // namespace caf
// </backward_compatibility>
#endif // CPPA_OPT_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CPPA_DETAIL_OPT_IMPLS_HPP
#define CPPA_DETAIL_OPT_IMPLS_HPP
#include <sstream>
#include "caf/on.hpp"
#include "caf/optional.hpp"
// this header contains implementation details for opt.hpp
namespace caf {
namespace detail {
template <class T>
struct conv_arg_impl {
using result_type = optional<T>;
static inline result_type _(const std::string& arg) {
std::istringstream iss(arg);
T result;
if (iss >> result && iss.eof()) {
return result;
}
return none;
}
};
template <>
struct conv_arg_impl<std::string> {
using result_type = optional<std::string>;
static inline result_type _(const std::string& arg) { return arg; }
};
template <class T>
struct conv_arg_impl<optional<T>> {
using result_type = optional<T>;
static inline result_type _(const std::string& arg) {
return conv_arg_impl<T>::_(arg);
}
};
template <bool>
class opt1_rvalue_builder;
template <class T>
struct rd_arg_storage : ref_counted {
T& storage;
bool set;
std::string arg_name;
rd_arg_storage(T& r) : storage(r), set(false) {
// nop
}
};
template <class T>
class rd_arg_functor {
public:
template <bool>
friend class opt1_rvalue_builder;
using storage_type = rd_arg_storage<T>;
rd_arg_functor(const rd_arg_functor&) = default;
rd_arg_functor(T& storage) : m_storage(new storage_type(storage)) {
// nop
}
bool operator()(const std::string& arg) const {
if (m_storage->set) {
std::cerr << "*** error: " << m_storage->arg_name
<< " already defined" << std::endl;
return false;
}
auto opt = conv_arg_impl<T>::_(arg);
if (!opt) {
std::cerr << "*** error: cannot convert \"" << arg << "\" to "
<< typeid(T).name()
<< " [option: \"" << m_storage->arg_name << "\"]"
<< std::endl;
return false;
}
m_storage->storage = *opt;
m_storage->set = true;
return true;
}
private:
intrusive_ptr<storage_type> m_storage;
};
template <class T>
class add_arg_functor {
public:
template <bool>
friend class opt1_rvalue_builder;
using value_type = std::vector<T>;
using storage_type = rd_arg_storage<value_type>;
add_arg_functor(const add_arg_functor&) = default;
add_arg_functor(value_type& storage) : m_storage(new storage_type(storage)) {
// nop
}
bool operator()(const std::string& arg) const {
auto opt = conv_arg_impl<T>::_(arg);
if (!opt) {
std::cerr << "*** error: cannot convert \"" << arg << "\" to "
<< typeid(T).name()
<< " [option: \"" << m_storage->arg_name << "\"]"
<< std::endl;
return false;
}
m_storage->storage.push_back(*opt);
return true;
}
private:
intrusive_ptr<storage_type> m_storage;
};
template <class T>
struct is_rd_arg : std::false_type { };
template <class T>
struct is_rd_arg<rd_arg_functor<T>> : std::true_type { };
template <class T>
struct is_rd_arg<add_arg_functor<T>> : std::true_type { };
using opt0_rvalue_builder = decltype(on<std::string>());
template <bool HasShortOpt = true>
class opt1_rvalue_builder {
public:
using left_type = decltype(on<std::string, std::string>());
using right_type =
decltype(on(std::function<optional<std::string> (const std::string&)>()));
template <class Left, typename Right>
opt1_rvalue_builder(char sopt, std::string lopt, Left&& lhs, Right&& rhs)
: m_short(sopt),
m_long(std::move(lopt)),
m_left(std::forward<Left>(lhs)),
m_right(std::forward<Right>(rhs)) {
// nop
}
template <class Expr>
auto operator>>(Expr expr)
-> decltype((*(static_cast<left_type*>(nullptr)) >> expr).or_else(
*(static_cast<right_type*>(nullptr)) >> expr)) const {
inject_arg_name(expr);
return (m_left >> expr).or_else(m_right >> expr);
}
private:
template <class T>
void inject_arg_name(rd_arg_functor<T>& expr) {
expr.m_storage->arg_name = m_long;
}
template <class T>
void inject_arg_name(const T&) {
// using opts without rd_arg() or similar functor
}
char m_short;
std::string m_long;
left_type m_left;
right_type m_right;
};
template <>
class opt1_rvalue_builder<false> {
public:
using sub_type =
decltype(on(std::function<optional<std::string> (const std::string&)>()));
template <class SubType>
opt1_rvalue_builder(std::string lopt, SubType&& sub)
: m_long(std::move(lopt)),
m_sub(std::forward<SubType>(sub)) {
// nop
}
template <class Expr>
auto operator>>(Expr expr)
-> decltype(*static_cast<sub_type*>(nullptr) >> expr) const {
inject_arg_name(expr);
return m_sub >> expr;
}
private:
template <class T>
inline void inject_arg_name(rd_arg_functor<T>& expr) {
expr.m_storage->arg_name = m_long;
}
template <class T>
inline void inject_arg_name(const T&) {
// using opts without rd_arg() or similar functor
}
std::string m_long;
sub_type m_sub;
};
} // namespace detail
} // namespace caf
#endif // CPPA_DETAIL_OPT_IMPLS_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CPPA_PUBLISH_LOCAL_GROUPS_HPP
#define CPPA_PUBLISH_LOCAL_GROUPS_HPP
// <backward_compatibility version="0.9" whole_file="yes">
#include "caf/io/publish_local_groups.hpp"
namespace caf {
// import into caf for the sake of backwart compatibility
using io::publish_local_groups;
} // namespace caf
// </backward_compatibility>
#endif // CPPA_PUBLISH_LOCAL_GROUPS_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/io/spawn_io.hpp"
namespace caf {
// import io::spawn_io for backward compatbility reasons
using io::spawn_io;
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CPPA_TUPLE_CAST_HPP
#define CPPA_TUPLE_CAST_HPP
// <backward_compatibility version="0.9" whole_file="yes">
#include <type_traits>
#include "caf/message.hpp"
#include "caf/optional.hpp"
#include "caf/wildcard_position.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/types_array.hpp"
#include "caf/detail/decorated_tuple.hpp"
#include "cppa/cow_tuple.hpp"
namespace caf {
template <class TupleIter, class PatternIter,
class Push, class Commit, class Rollback>
bool dynamic_match(TupleIter tbegin, TupleIter tend,
PatternIter pbegin, PatternIter pend,
Push& push, Commit& commit, Rollback& rollback) {
while (!(pbegin == pend && tbegin == tend)) {
if (pbegin == pend) {
// reached end of pattern while some values remain unmatched
return false;
}
else if (*pbegin == nullptr) { // nullptr == wildcard (anything)
// perform submatching
++pbegin;
// always true at the end of the pattern
if (pbegin == pend) return true;
// safe current mapping as fallback
commit();
// iterate over tuple values until we found a match
for (; tbegin != tend; ++tbegin) {
if (dynamic_match(tbegin, tend, pbegin, pend,
push, commit, rollback)) {
return true;
}
// restore mapping to fallback (delete invalid mappings)
rollback();
}
return false; // no submatch found
}
// compare types
else if (tbegin.type() == *pbegin) push(tbegin);
// no match
else return false;
// next iteration
++tbegin;
++pbegin;
}
return true; // pbegin == pend && tbegin == tend
}
template <class... T>
auto moving_tuple_cast(message& tup)
-> optional<
typename cow_tuple_from_type_list<
typename detail::tl_filter_not<detail::type_list<T...>,
is_anything>::type
>::type> {
using result_type =
typename cow_tuple_from_type_list<
typename detail::tl_filter_not<detail::type_list<T...>, is_anything>::type
>::type;
using types = detail::type_list<T...>;
static constexpr auto impl =
get_wildcard_position<detail::type_list<T...>>();
auto& tarr = detail::static_types_array<T...>::arr;
const uniform_type_info* const* arr_pos = tarr.begin();
message sub;
switch (impl) {
case wildcard_position::nil: {
sub = tup;
break;
}
case wildcard_position::trailing: {
sub = tup.take(sizeof...(T) - 1);
break;
}
case wildcard_position::leading: {
++arr_pos; // skip leading 'anything'
sub = tup.take_right(sizeof...(T) - 1);
break;
}
case wildcard_position::in_between:
case wildcard_position::multiple: {
constexpr size_t wc_count =
detail::tl_count<detail::type_list<T...>, is_anything>::value;
if (tup.size() >= (sizeof...(T) - wc_count)) {
std::vector<size_t> mv; // mapping vector
size_t commited_size = 0;
auto fpush = [&](const typename message::const_iterator& iter) {
mv.push_back(iter.position());
};
auto fcommit = [&] {
commited_size = mv.size();
};
auto frollback = [&] {
mv.resize(commited_size);
};
if (dynamic_match(tup.begin(), tup.end(),
tarr.begin(), tarr.end(),
fpush, fcommit, frollback)) {
message msg{detail::decorated_tuple::create(
tup.vals(), std::move(mv))};
return result_type::from(msg);
}
return none;
}
break;
}
}
// same for nil, leading, and trailing
auto eq = [](const detail::message_iterator& lhs,
const uniform_type_info* rhs) {
return lhs.type() == rhs;
};
if (std::equal(sub.begin(), sub.end(), arr_pos, eq)) {
return result_type::from(sub);
}
return none;
}
template <class... T>
auto moving_tuple_cast(message& tup, const detail::type_list<T...>&)
-> decltype(moving_tuple_cast<T...>(tup)) {
return moving_tuple_cast<T...>(tup);
}
template <class... T>
auto tuple_cast(message tup)
-> optional<
typename cow_tuple_from_type_list<
typename detail::tl_filter_not<detail::type_list<T...>,
is_anything>::type
>::type> {
return moving_tuple_cast<T...>(tup);
}
template <class... T>
auto tuple_cast(message tup, const detail::type_list<T...>&)
-> decltype(tuple_cast<T...>(tup)) {
return moving_tuple_cast<T...>(tup);
}
template <class... T>
auto unsafe_tuple_cast(message& tup, const detail::type_list<T...>&)
-> decltype(tuple_cast<T...>(tup)) {
return tuple_cast<T...>(tup);
}
} // namespace caf
// </backward_compatibility>
#endif // CPPA_TUPLE_CAST_HPP
......@@ -48,20 +48,20 @@ using guard_type = std::unique_lock<std::mutex>;
// by std::atomic<> constructor
abstract_actor::abstract_actor(actor_id aid, node_id nid, size_t initial_count)
: super(std::move(nid), initial_count),
: super(abstract_channel::is_abstract_actor_flag,
std::move(nid), initial_count),
m_id(aid),
m_exit_reason(exit_reason::not_exited),
m_host(nullptr),
m_flags(0) {
m_host(nullptr) {
// nop
}
abstract_actor::abstract_actor(size_t initial_count)
: super(detail::singletons::get_node_id(), initial_count),
: super(abstract_channel::is_abstract_actor_flag,
detail::singletons::get_node_id(), initial_count),
m_id(detail::singletons::get_actor_registry()->next_id()),
m_exit_reason(exit_reason::not_exited),
m_host(nullptr),
m_flags(0) {
m_host(nullptr) {
// nop
}
......
......@@ -24,14 +24,18 @@ namespace caf {
using detail::singletons;
abstract_channel::abstract_channel(size_t initial_ref_count)
abstract_channel::abstract_channel(channel_type_flag subtype,
size_t initial_ref_count)
: ref_counted(initial_ref_count),
m_flags(static_cast<int>(subtype)),
m_node(singletons::get_node_id()) {
// nop
}
abstract_channel::abstract_channel(node_id nid, size_t initial_ref_count)
abstract_channel::abstract_channel(channel_type_flag subtype, node_id nid,
size_t initial_ref_count)
: ref_counted(initial_ref_count),
m_flags(static_cast<int>(subtype)),
m_node(std::move(nid)) {
// nop
}
......
......@@ -37,11 +37,14 @@ void abstract_group::subscription::actor_exited(abstract_actor* ptr, uint32_t) {
}
bool abstract_group::subscription::matches(const token& what) {
if (what.subtype != typeid(subscription_token)) {
if (what.subtype != attachable::token::subscription) {
return false;
}
auto& ot = *reinterpret_cast<const subscription_token*>(what.ptr);
return ot.group == m_group;
if (what.ptr) {
auto& ot = *reinterpret_cast<const subscription_token*>(what.ptr);
return ot.group == m_group;
}
return true;
}
abstract_group::module::module(std::string mname) : m_name(std::move(mname)) {
......@@ -53,7 +56,9 @@ const std::string& abstract_group::module::name() {
}
abstract_group::abstract_group(abstract_group::module_ptr mod, std::string id)
: m_module(mod), m_identifier(std::move(id)) {
: abstract_channel(abstract_channel::is_abstract_group_flag),
m_module(mod),
m_identifier(std::move(id)) {
// nop
}
......
......@@ -25,8 +25,8 @@ attachable::~attachable() {
// nop
}
attachable::token::token(const std::type_info& tinfo, const void* vptr)
: subtype(tinfo), ptr(vptr) {
attachable::token::token(size_t typenr, const void* vptr)
: subtype(typenr), ptr(vptr) {
// nop
}
......
......@@ -27,7 +27,9 @@ void* decorated_tuple::mutable_at(size_t pos) {
return m_decorated->mutable_at(m_mapping[pos]);
}
size_t decorated_tuple::size() const { return m_mapping.size(); }
size_t decorated_tuple::size() const {
return m_mapping.size();
}
decorated_tuple* decorated_tuple::copy() const {
return new decorated_tuple(*this);
......@@ -38,62 +40,56 @@ const void* decorated_tuple::at(size_t pos) const {
return m_decorated->at(m_mapping[pos]);
}
const uniform_type_info* decorated_tuple::type_at(size_t pos) const {
CAF_REQUIRE(pos < size());
return m_decorated->type_at(m_mapping[pos]);
bool decorated_tuple::match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const {
return m_decorated->match_element(m_mapping[pos], typenr, rtti);
}
uint32_t decorated_tuple::type_token() const {
return m_type_token;
}
auto decorated_tuple::type_token() const -> rtti {
return m_token;
const char* decorated_tuple::uniform_name_at(size_t pos) const {
return m_decorated->uniform_name_at(m_mapping[pos]);
}
uint16_t decorated_tuple::type_nr_at(size_t pos) const {
return m_decorated->type_nr_at(m_mapping[pos]);
}
void decorated_tuple::init() {
CAF_REQUIRE(m_mapping.empty()
|| *(std::max_element(m_mapping.begin(), m_mapping.end()))
< static_cast<const pointer&>(m_decorated)->size());
// calculate type token
for (size_t i = 0; i < m_mapping.size(); ++i) {
m_type_token <<= 6;
m_type_token |= m_decorated->type_nr_at(m_mapping[i]);
}
}
void decorated_tuple::init(size_t offset) {
const pointer& dec = m_decorated;
if (offset < dec->size()) {
if (offset < m_decorated->size()) {
size_t i = offset;
m_mapping.resize(dec->size() - offset);
size_t new_size = m_decorated->size() - offset;
m_mapping.resize(new_size);
std::generate(m_mapping.begin(), m_mapping.end(), [&] { return i++; });
}
init();
}
decorated_tuple::decorated_tuple(pointer d, vector_type&& v)
: super(true),
m_decorated(std::move(d)),
m_token(&typeid(void)),
m_mapping(std::move(v)) {
init();
}
decorated_tuple::decorated_tuple(pointer d, rtti ti, vector_type&& v)
: super(false),
m_decorated(std::move(d)),
m_token(ti),
m_mapping(std::move(v)) {
: m_decorated(std::move(d)),
m_mapping(std::move(v)),
m_type_token(0xFFFFFFFF) {
init();
}
decorated_tuple::decorated_tuple(pointer d, size_t offset)
: super(true), m_decorated(std::move(d)), m_token(&typeid(void)) {
: m_decorated(std::move(d)),
m_type_token(0xFFFFFFFF) {
init(offset);
}
decorated_tuple::decorated_tuple(pointer d, rtti ti, size_t offset)
: super(false), m_decorated(std::move(d)), m_token(ti) {
init(offset);
}
const std::string* decorated_tuple::tuple_type_names() const {
// produced name is equal for all instances
static std::string result = get_tuple_type_names(*this);
return &result;
}
} // namespace detail
} // namespace caf
......@@ -37,14 +37,13 @@ message make(abstract_actor* self, uint32_t reason) {
void default_attachable::actor_exited(abstract_actor* self, uint32_t reason) {
CAF_REQUIRE(self->address() != m_observer);
auto factory = m_type == monitor ? &make<down_msg> : &make<exit_msg>;
message msg = factory(self, reason);
auto ptr = actor_cast<abstract_actor_ptr>(m_observer);
ptr->enqueue(self->address(), message_id{}.with_high_priority(),
msg, self->host());
factory(self, reason), self->host());
}
bool default_attachable::matches(const token& what) {
if (what.subtype != typeid(observe_token)) {
if (what.subtype != attachable::token::observer) {
return false;
}
auto& ot = *reinterpret_cast<const observe_token*>(what.ptr);
......
......@@ -57,7 +57,7 @@ void local_actor::demonitor(const actor_addr& whom) {
}
auto ptr = actor_cast<abstract_actor_ptr>(whom);
default_attachable::observe_token tk{address(), default_attachable::monitor};
ptr->detach({typeid(default_attachable::observe_token), &tk});
ptr->detach(tk);
}
void local_actor::join(const group& what) {
......@@ -88,11 +88,12 @@ void local_actor::leave(const group& what) {
std::vector<group> local_actor::joined_groups() const {
std::vector<group> result;
result.reserve(20);
attachable::token stk{attachable::token::subscription, nullptr};
std::unique_lock<std::mutex> guard{m_mtx};
for (attachable* i = m_attachables_head.get(); i != 0; i = i->next.get()) {
auto sptr = dynamic_cast<abstract_group::subscription*>(i);
if (sptr) {
result.emplace_back(sptr->group());
if (i->matches(stk)) {
auto ptr = static_cast<abstract_group::subscription*>(i);
result.emplace_back(ptr->group());
}
}
return result;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <vector>
#include <string>
#include <sstream>
#include "caf/match.hpp"
using namespace std;
namespace caf {
detail::match_helper match_split(const std::string& str, char delim,
bool keep_empties) {
message_builder result;
stringstream strs(str);
string tmp;
while (getline(strs, tmp, delim)) {
if (!tmp.empty() && !keep_empties) {
result.append(std::move(tmp));
}
}
return result.to_message();
}
} // namespace caf
......@@ -18,7 +18,11 @@
******************************************************************************/
#include "caf/message.hpp"
#include <iostream>
#include "caf/message_handler.hpp"
#include "caf/string_algorithms.hpp"
#include "caf/detail/singletons.hpp"
#include "caf/detail/decorated_tuple.hpp"
......@@ -56,9 +60,13 @@ const void* message::at(size_t p) const {
return m_vals->at(p);
}
const uniform_type_info* message::type_at(size_t p) const {
CAF_REQUIRE(m_vals);
return m_vals->type_at(p);
bool message::match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const {
return m_vals->match_element(pos, typenr, rtti);
}
const char* message::uniform_name_at(size_t pos) const {
return m_vals->uniform_name_at(pos);
}
bool message::equals(const message& other) const {
......@@ -86,32 +94,174 @@ message message::drop_right(size_t n) const {
return message{};
}
std::vector<size_t> mapping(size() - n);
size_t i = 0;
std::generate(mapping.begin(), mapping.end(), [&] { return i++; });
std::iota(mapping.begin(), mapping.end(), size_t{0});
return message{detail::decorated_tuple::create(m_vals, std::move(mapping))};
}
optional<message> message::apply(message_handler handler) {
return handler(*this);
message message::slice(size_t pos, size_t n) const {
auto s = size();
if (pos >= s) {
return message{};
}
std::vector<size_t> mapping(std::min(s - pos, n));
std::iota(mapping.begin(), mapping.end(), pos);
return message{detail::decorated_tuple::create(m_vals, std::move(mapping))};
}
const std::type_info* message::type_token() const {
return m_vals ? m_vals->type_token() : &typeid(detail::empty_type_list);
optional<message> message::apply(message_handler handler) {
return handler(*this);
}
bool message::dynamically_typed() const {
return m_vals ? m_vals->dynamically_typed() : false;
message message::filter_impl(size_t start, message_handler handler) const {
auto s = size();
for (size_t i = start; i < s; ++i) {
for (size_t n = (s - i) ; n > 0; --n) {
auto res = handler(slice(i, n));
if (res) {
std::vector<size_t> mapping(s);
std::iota(mapping.begin(), mapping.end(), size_t{0});
auto first = mapping.begin() + static_cast<ptrdiff_t>(i);
auto last = first + static_cast<ptrdiff_t>(n);
mapping.erase(first, last);
if (mapping.empty()) {
return message{};
}
message next{detail::decorated_tuple::create(m_vals,
std::move(mapping))};
return next.filter_impl(i, handler);
}
}
}
return *this;
}
message::const_iterator message::begin() const {
return m_vals ? m_vals->begin() : const_iterator{nullptr, 0};
message message::filter(message_handler handler) const {
return filter_impl(0, handler);
}
/**
* Returns an iterator to the end.
*/
message::const_iterator message::end() const {
return m_vals ? m_vals->end() : const_iterator{nullptr, 0};
message::cli_res message::filter_cli(std::vector<cli_arg> cliargs) const {
std::set<std::string> opts;
cli_arg dummy{"help,h", ""};
std::map<std::string, cli_arg*> shorts;
std::map<std::string, cli_arg*> longs;
shorts["-h"] = &dummy;
shorts["-?"] = &dummy;
longs["--help"] = &dummy;
for (auto& cliarg : cliargs) {
std::vector<std::string> s;
split(s, cliarg.name, is_any_of(","), token_compress_on);
if (s.size() == 2 && s.back().size() == 1) {
longs["--" + s.front()] = &cliarg;
shorts["-" + s.back()] = &cliarg;
} else if (s.size() == 1) {
longs[s.front()] = &cliarg;
} else {
throw std::invalid_argument("invalid option name: " + cliarg.name);
}
}
auto insert_opt_name = [&](const cli_arg* ptr) {
auto separator = ptr->name.find(',');
if (separator == std::string::npos) {
opts.insert(ptr->name);
} else {
opts.insert(ptr->name.substr(0, separator));
}
};
auto res = filter({
[&](const std::string& arg) -> optional<skip_message_t> {
if (arg.empty() || arg.front() != '-') {
return skip_message();
}
auto i = shorts.find(arg);
if (i != shorts.end()) {
if (i->second->fun) {
return skip_message();
}
insert_opt_name(i->second);
return none;
}
auto eq_pos = arg.find('=');
auto j = longs.find(arg.substr(0, eq_pos));
if (j != longs.end()) {
if (j->second->fun) {
if (eq_pos == std::string::npos) {
std::cerr << "missing argument to " << arg << std::endl;
return none;
}
if (!j->second->fun(arg.substr(eq_pos + 1))) {
std::cerr << "invalid value for option "
<< j->second->name << ": " << arg << std::endl;
return none;
}
insert_opt_name(j->second);
return none;
}
insert_opt_name(j->second);
return none;
}
std::cerr << "unknown command line option: " << arg << std::endl;
return none;
},
[&](const std::string& arg1,
const std::string& arg2) -> optional<skip_message_t> {
if (arg1.size() < 2 || arg1[0] != '-' || arg1[1] == '-') {
return skip_message();
}
auto i = shorts.find(arg1);
if (i != shorts.end() && i->second->fun) {
if (!i->second->fun(arg2)) {
std::cerr << "invalid value for option "
<< i->second->name << ": " << arg2 << std::endl;
return none;
}
insert_opt_name(i->second);
return none;
}
std::cerr << "unknown command line option: " << arg1 << std::endl;
return none;
}
});
size_t name_width = 0;
for (auto& ca : cliargs) {
// name field contains either only "--<long_name>" or
// "-<short name> [--<long name>]" depending on whether or not
// a ',' appears in the name
auto nw = ca.name.find(',') == std::string::npos
? ca.name.size() + 2 // "--<name>"
: ca.name.size() + 5; // "-X [--<name>]" (minus trailing ",X")
if (ca.fun) {
nw += 4; // trailing " arg"
}
name_width = std::max(name_width, nw);
}
std::ostringstream oss;
oss << std::left;
oss << "Allowed options:" << std::endl;
for (auto& ca : cliargs) {
std::string lhs;
auto separator = ca.name.find(',');
if (separator == std::string::npos) {
lhs += "--";
lhs += ca.name;
} else {
lhs += "-";
lhs += ca.name.back();
lhs += " [--";
lhs += ca.name.substr(0, separator);
lhs += "]";
}
if (ca.fun) {
lhs += " arg";
}
oss << " ";
oss.width(static_cast<std::streamsize>(name_width));
oss << lhs << " : " << ca.text << std::endl;
}
auto helptext = oss.str();
if (opts.count("help") == 1) {
std::cout << helptext << std::endl;
}
return {res, std::move(opts), std::move(helptext)};
}
} // namespace caf
......@@ -29,21 +29,23 @@ class message_builder::dynamic_msg_data : public detail::message_data {
public:
using super = message_data;
using message_data::const_iterator;
dynamic_msg_data() : super(true) {
dynamic_msg_data() : m_type_token(0xFFFFFFFF) {
// nop
}
dynamic_msg_data(const dynamic_msg_data& other) : super(true) {
for (auto& d : other.m_elements) {
m_elements.push_back(d->copy());
dynamic_msg_data(const dynamic_msg_data& other) : m_type_token(0xFFFFFFFF) {
for (auto& e : other.m_elements) {
add_to_type_token(e->ti->type_nr());
m_elements.push_back(e->copy());
}
}
dynamic_msg_data(std::vector<uniform_value>&& data)
: super(true), m_elements(std::move(data)) {
// nop
: m_elements(std::move(data)),
m_type_token(0xFFFFFFFF) {
for (auto& e : m_elements) {
add_to_type_token(e->ti->type_nr());
}
}
~dynamic_msg_data();
......@@ -66,16 +68,39 @@ class message_builder::dynamic_msg_data : public detail::message_data {
return new dynamic_msg_data(*this);
}
const uniform_type_info* type_at(size_t pos) const override {
CAF_REQUIRE(pos < size());
return m_elements[pos]->ti;
bool match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const override {
CAF_REQUIRE(typenr != 0 || rtti != nullptr);
auto uti = m_elements[pos]->ti;
if (uti->type_nr() != typenr) {
return false;
}
return typenr != 0 || uti->equal_to(*rtti);
}
const char* uniform_name_at(size_t pos) const override {
return m_elements[pos]->ti->name();
}
uint16_t type_nr_at(size_t pos) const override {
return m_elements[pos]->ti->type_nr();
}
uint32_t type_token() const override {
return m_type_token;
}
void append(uniform_value&& what) {
add_to_type_token(what->ti->type_nr());
m_elements.push_back(std::move(what));
}
const std::string* tuple_type_names() const override {
return nullptr; // get_tuple_type_names(*this);
void add_to_type_token(uint16_t typenr) {
m_type_token = (m_type_token << 6) | typenr;
}
std::vector<uniform_value> m_elements;
uint32_t m_type_token;
};
message_builder::dynamic_msg_data::~dynamic_msg_data() {
......@@ -110,7 +135,7 @@ bool message_builder::empty() const {
}
message_builder& message_builder::append(uniform_value what) {
data()->m_elements.push_back(std::move(what));
data()->append(std::move(what));
return *this;
}
......
......@@ -19,30 +19,37 @@
#include "caf/detail/message_data.hpp"
#include <cstring>
namespace caf {
namespace detail {
message_data::message_data(bool is_dynamic) : m_is_dynamic(is_dynamic) {
// nop
}
bool message_data::equals(const message_data& other) const {
auto full_eq = [](const message_iterator& lhs, const message_iterator& rhs) {
return lhs.type() == rhs.type()
&& lhs.type()->equals(lhs.value(), rhs.value());
};
return this == &other
|| (size() == other.size()
&& std::equal(begin(), end(), other.begin(), full_eq));
}
message_data::message_data(const message_data& other)
: super(), m_is_dynamic(other.m_is_dynamic) {
// nop
}
const std::type_info* message_data::type_token() const {
return &typeid(void);
if (this == &other) {
return true;
}
auto n = size();
if (n != other.size()) {
return false;
}
// step 1, get and compare type names
std::vector<const char*> type_names;
for (size_t i = 0; i < n; ++i) {
auto lhs = uniform_name_at(i);
auto rhs = other.uniform_name_at(i);
if (lhs != rhs && strcmp(lhs, rhs) != 0) {
return false; // type mismatch
}
type_names.push_back(lhs);
}
// step 2: compare each value individually
for (size_t i = 0; i < n; ++i) {
auto uti = uniform_type_info::from(type_names[i]);
if (!uti->equals(at(i), other.at(i))) {
return false;
}
}
return true;
}
const void* message_data::native_data() const {
......@@ -53,12 +60,11 @@ void* message_data::mutable_native_data() {
return nullptr;
}
std::string get_tuple_type_names(const detail::message_data& tup) {
std::string message_data::tuple_type_names() const {
std::string result = "@<>";
for (size_t i = 0; i < tup.size(); ++i) {
auto uti = tup.type_at(i);
for (size_t i = 0; i < size(); ++i) {
result += "+";
result += uti->name();
result += uniform_name_at(i);
}
return result;
}
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/detail/message_iterator.hpp"
#include "caf/detail/message_data.hpp"
namespace caf {
namespace detail {
message_iterator::message_iterator(const_pointer dataptr, size_t pos)
: m_pos(pos),
m_data(dataptr) {
// nop
}
const void* message_iterator::value() const {
return m_data->at(m_pos);
}
const uniform_type_info* message_iterator::type() const {
return m_data->type_at(m_pos);
}
} // namespace detail
} // namespace caf
......@@ -25,38 +25,36 @@ namespace detail {
using pattern_iterator = const meta_element*;
bool is_wildcard(const meta_element& me) {
return me.type == nullptr;
return me.typenr == 0 && me.type == nullptr;
}
bool match_element(const atom_value&, const std::type_info* type,
const message_iterator& iter, void** storage) {
if (!iter.type()->equal_to(*type)) {
bool match_element(const meta_element& me, const message& msg,
size_t pos, void** storage) {
CAF_REQUIRE(me.typenr != 0 || me.type != nullptr);
if (!msg.match_element(pos, me.typenr, me.type)) {
return false;
}
if (storage) {
*storage = const_cast<void*>(iter.value());
}
*storage = const_cast<void*>(msg.at(pos));
return true;
}
bool match_atom_constant(const atom_value& value, const std::type_info* type,
const message_iterator& iter, void** storage) {
auto uti = iter.type();
if (!uti->equal_to(*type)) {
bool match_atom_constant(const meta_element& me, const message& msg,
size_t pos, void** storage) {
CAF_REQUIRE(me.typenr == detail::type_nr<atom_value>::value);
if (!msg.match_element(pos, detail::type_nr<atom_value>::value, nullptr)) {
return false;
}
if (storage) {
if (!uti->equals(iter.value(), &value)) {
return false;
}
// This assignment casts `uniform_type_info*` to `atom_constant<V>*`.
// This type violation could theoretically cause undefined behavior.
// However, `uti` does have an address that is guaranteed to be valid
// throughout the runtime of the program and the atom constant
// does not have any members. Hence, this is nonetheless safe since
// we are never actually going to dereference the pointer.
*storage = const_cast<void*>(reinterpret_cast<const void*>(uti));
auto ptr = msg.at(pos);
if (me.v != *reinterpret_cast<const atom_value*>(ptr)) {
return false;
}
// This assignment casts `atom_value` to `atom_constant<V>*`.
// This type violation could theoretically cause undefined behavior.
// However, `uti` does have an address that is guaranteed to be valid
// throughout the runtime of the program and the atom constant
// does not have any members. Hence, this is nonetheless safe since
// we are never actually going to dereference the pointer.
*storage = const_cast<void*>(ptr);
return true;
}
......@@ -72,7 +70,7 @@ class set_commit_rollback {
++m_pos;
}
inline pointer current() {
return m_data? &m_data[m_pos] : nullptr;
return &m_data[m_pos];
}
inline void commit() {
m_fallback_pos = m_pos;
......@@ -86,10 +84,10 @@ class set_commit_rollback {
size_t m_fallback_pos;
};
bool try_match(message_iterator mbegin, message_iterator mend,
bool try_match(const message& msg, size_t msg_pos, size_t msg_size,
pattern_iterator pbegin, pattern_iterator pend,
set_commit_rollback& storage) {
while (mbegin != mend) {
while (msg_pos < msg_size) {
if (pbegin == pend) {
return false;
}
......@@ -103,8 +101,8 @@ bool try_match(message_iterator mbegin, message_iterator mend,
// safe current mapping as fallback
storage.commit();
// iterate over remaining values until we found a match
for (; mbegin != mend; ++mbegin) {
if (try_match(mbegin, mend, pbegin, pend, storage)) {
for (; msg_pos < msg_size; ++msg_pos) {
if (try_match(msg, msg_pos, msg_size, pbegin, pend, storage)) {
return true;
}
// restore mapping to fallback (delete invalid mappings)
......@@ -113,13 +111,13 @@ bool try_match(message_iterator mbegin, message_iterator mend,
return false; // no submatch found
}
// inspect current element
if (!pbegin->fun(pbegin->v, pbegin->type, mbegin, storage.current())) {
if (!pbegin->fun(*pbegin, msg, msg_pos, storage.current())) {
// type mismatch
return false;
}
// next iteration
storage.inc();
++mbegin;
++msg_pos;
++pbegin;
}
// we found a match if we've inspected each element and consumed
......@@ -128,9 +126,10 @@ bool try_match(message_iterator mbegin, message_iterator mend,
}
bool try_match(const message& msg, pattern_iterator pb, size_t ps, void** out) {
CAF_REQUIRE(out != nullptr);
CAF_REQUIRE(msg.empty() || msg.vals()->get_reference_count() > 0);
set_commit_rollback scr{out};
auto res = try_match(msg.begin(), msg.end(), pb, pb + ps, scr);
return res;
return try_match(msg, 0, msg.size(), pb, pb + ps, scr);
}
} // namespace detail
......
......@@ -58,9 +58,13 @@ uniform_value_t::~uniform_value_t() {
// nop
}
const uniform_type_info* announce(const std::type_info&,
uniform_type_info_ptr utype) {
return uti_map().insert(std::move(utype));
const uniform_type_info* announce(const std::type_info& ti,
uniform_type_info_ptr utype) {
return uti_map().insert(&ti, std::move(utype));
}
uniform_type_info::uniform_type_info(uint16_t typenr) : m_type_nr(typenr) {
// nop
}
uniform_type_info::~uniform_type_info() {
......@@ -97,6 +101,11 @@ std::vector<const uniform_type_info*> uniform_type_info::instances() {
return uti_map().get_all();
}
const uniform_type_info* uniform_typeid_by_nr(uint16_t nr) {
CAF_REQUIRE(nr > 0 && nr < detail::type_nrs);
return uti_map().by_type_nr(nr);
}
const uniform_type_info* uniform_typeid(const std::type_info& tinf,
bool allow_nullptr) {
auto result = uti_map().by_rtti(tinf);
......
This diff is collapsed.
......@@ -273,7 +273,7 @@ void basp_broker::local_dispatch(const basp::header& hdr, message&& msg) {
CAF_REQUIRE(!dest || dest->node() == node());
// intercept message used for link signaling
if (dest && src == dest) {
if (msg.size() == 2 && typeid(actor_addr) == *msg.type_at(1)) {
if (msg.match_elements<atom_value, actor_addr>()) {
actor_addr other;
bool is_unlink = true;
// extract arguments
......
......@@ -116,54 +116,21 @@ deserialize_impl(T& dm, deserializer* source) {
}
template <class T>
class uti_impl : public uniform_type_info {
class uti_impl : public detail::abstract_uniform_type_info<T> {
public:
uti_impl(const char* tname) : m_native(&typeid(T)), m_name(tname) {
// nop
}
using super = detail::abstract_uniform_type_info<T>;
bool equal_to(const std::type_info& ti) const override {
// in some cases (when dealing with dynamic libraries),
// address can be different although types are equal
return m_native == &ti || *m_native == ti;
}
bool equals(const void* lhs, const void* rhs) const override {
return deref(lhs) == deref(rhs);
}
uniform_value create(const uniform_value& other) const override {
return this->create_impl<T>(other);
}
message as_message(void* instance) const override {
return make_message(deref(instance));
}
const char* name() const {
return m_name.c_str();
uti_impl(const char* tname) : super(tname) {
// nop
}
protected:
void serialize(const void* instance, serializer* sink) const {
serialize_impl(deref(instance), sink);
serialize_impl(super::deref(instance), sink);
}
void deserialize(void* instance, deserializer* source) const {
deserialize_impl(deref(instance), source);
}
private:
static inline T& deref(void* ptr) {
return *reinterpret_cast<T*>(ptr);
}
static inline const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(ptr);
deserialize_impl(super::deref(instance), source);
}
const std::type_info* m_native;
std::string m_name;
};
template <class T>
......
......@@ -21,6 +21,7 @@ add_unit_test(atom)
add_unit_test(metaprogramming)
add_unit_test(intrusive_containers)
add_unit_test(match)
add_unit_test(message)
add_unit_test(serialization)
add_unit_test(uniform_type)
add_unit_test(fixed_vector)
......
......@@ -11,30 +11,39 @@ using namespace caf;
namespace {
std::atomic<long> s_testees;
std::atomic<long> s_pending_on_exits;
} // namespace <anonymous>
class testee : public event_based_actor {
public:
testee() {
++s_testees;
}
testee();
~testee();
behavior make_behavior() {
return {
others() >> [=] {
return last_dequeued();
}
};
}
void on_exit();
behavior make_behavior() override;
};
testee::testee() {
++s_testees;
++s_pending_on_exits;
}
testee::~testee() {
// avoid weak-vtables warning
--s_testees;
}
void testee::on_exit() {
--s_pending_on_exits;
}
behavior testee::make_behavior() {
return {
others() >> [=] {
return last_dequeued();
}
};
}
template <class ExitMsgType>
behavior tester(event_based_actor* self, const actor& aut) {
CAF_CHECKPOINT();
......@@ -48,9 +57,12 @@ behavior tester(event_based_actor* self, const actor& aut) {
anon_send_exit(aut, exit_reason::user_shutdown);
CAF_CHECKPOINT();
return {
[self](const ExitMsgType&) {
[self](const ExitMsgType& msg) {
// must be still alive at this point
CAF_CHECK_EQUAL(s_testees.load(), 1);
CAF_CHECK_EQUAL(msg.reason, exit_reason::user_shutdown);
CAF_CHECK_EQUAL(self->last_dequeued().vals()->get_reference_count(), 1);
CAF_CHECK(&msg == self->last_dequeued().at(0));
// testee might be still running its cleanup code in
// another worker thread; by waiting some milliseconds, we make sure
// testee had enough time to return control to the scheduler
......@@ -59,18 +71,22 @@ behavior tester(event_based_actor* self, const actor& aut) {
check_atom::value);
},
[self](check_atom) {
// make sure dude's dtor has been called
// make sure aut's dtor and on_exit() have been called
CAF_CHECK_EQUAL(s_testees.load(), 0);
CAF_CHECK_EQUAL(s_pending_on_exits.load(), 0);
self->quit();
}
};
}
#define BREAK_ON_ERROR() if (CAF_TEST_RESULT() > 0) return
template <spawn_options O1, spawn_options O2>
void run() {
CAF_PRINT("run test using links");
spawn<O1>(tester<exit_msg>, spawn<testee, O2>());
await_all_actors_done();
BREAK_ON_ERROR();
CAF_PRINT("run test using monitors");
spawn<O1>(tester<down_msg>, spawn<testee, O2>());
await_all_actors_done();
......@@ -79,10 +95,13 @@ void run() {
void test_actor_lifetime() {
CAF_PRINT("run<no_spawn_options, no_spawn_options>");
run<no_spawn_options, no_spawn_options>();
BREAK_ON_ERROR();
CAF_PRINT("run<detached, no_spawn_options>");
run<detached, no_spawn_options>();
BREAK_ON_ERROR();
CAF_PRINT("run<no_spawn_options, detached>");
run<no_spawn_options, detached>();
BREAK_ON_ERROR();
CAF_PRINT("run<detached, detached>");
run<detached, detached>();
}
......@@ -90,6 +109,5 @@ void test_actor_lifetime() {
int main() {
CAF_TEST(test_actor_lifetime);
test_actor_lifetime();
CAF_CHECK_EQUAL(s_testees.load(), 0);
return CAF_TEST_RESULT();
}
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