Commit 1a32df0c authored by Dominik Charousset's avatar Dominik Charousset

Fix build on MSVC

parent 178dff5f
......@@ -6,6 +6,12 @@ if(APPLE AND NOT DEFINED CMAKE_MACOSX_RPATH)
set(CMAKE_MACOSX_RPATH true)
endif()
# shared libs currently not supported on Windows
if(WIN32 AND NOT CAF_BUILD_STATIC_ONLY)
message(STATUS "CAF currently only supports static-only builds on Windows")
set(CAF_BUILD_STATIC_ONLY yes)
endif()
################################################################################
# make sure all variables are set to "no" if undefined for summary output #
################################################################################
......
Subproject commit 03bb8aea85332589a426d4b71163c9aa30044ce3
Subproject commit 9b59c80bc35dfcbb75c016de5ea475695ec8c64b
......@@ -17,7 +17,7 @@ using namespace caf;
namespace {
using add_atom = atom_constant<atom("add")>;
// using add_atom = atom_constant<atom("add")>; (defined in atom.hpp)
using multiply_atom = atom_constant<atom("multiply")>;
using adder = typed_actor<replies_to<add_atom, int, int>::with<int>>;
......
......@@ -8,7 +8,7 @@
using std::endl;
using namespace caf;
using add_atom = atom_constant<atom("add")>;
// using add_atom = atom_constant<atom("add")>; (defined in atom.hpp)
using calc = typed_actor<replies_to<add_atom, int, int>::with<int>>;
......
......@@ -15,7 +15,7 @@ using std::endl;
using namespace caf;
using add_atom = atom_constant<atom("add")>;
// using add_atom = atom_constant<atom("add")>; (defined in atom.hpp)
using adder = typed_actor<replies_to<add_atom, int, int>::with<int>>;
......
......@@ -89,6 +89,18 @@ public:
const data_destructor data_dtor;
const block_destructor block_dtor;
static_assert(sizeof(std::atomic<size_t>) == sizeof(void*),
"std::atomic not lockfree on this platform");
static_assert(sizeof(intrusive_ptr<node_id::data>) == sizeof(void*),
"intrusive_ptr<T> and T* have different size");
static_assert(sizeof(node_id) == sizeof(void*),
"sizeof(node_id) != sizeof(size_t)");
static_assert(sizeof(data_destructor) == sizeof(void*),
"functiion pointer and regular pointers have different size");
/// Returns a pointer to the actual actor instance.
inline abstract_actor* get() {
// this pointer arithmetic is compile-time checked in actor_storage's ctor
......
......@@ -53,11 +53,13 @@ public:
"data is not at cache line size boundary");
// 4) make sure static_cast and reinterpret_cast
// between T* and abstract_actor* are identical
/*
constexpr abstract_actor* dummy = nullptr;
constexpr T* derived_dummy = static_cast<T*>(dummy);
static_assert(derived_dummy == nullptr,
"actor subtype has illegal memory alignment "
"(probably due to virtual inheritance)");
*/
// construct data member
new (&data) T(std::forward<Us>(zs)...);
}
......@@ -69,6 +71,9 @@ public:
actor_storage(const actor_storage&) = delete;
actor_storage& operator=(const actor_storage&) = delete;
static_assert(sizeof(actor_control_block) < CAF_CACHE_LINE_SIZE,
"actor_control_block exceeds 64 bytes");
actor_control_block ctrl;
char pad[CAF_CACHE_LINE_SIZE - sizeof(actor_control_block)];
union { T data; };
......
......@@ -39,9 +39,9 @@ struct output_types_of<typed_mpi<In, Out>> {
};
template <class T>
constexpr typename std::remove_pointer<T>::type::signatures signatures_of() {
return {};
}
struct signatures_of {
using type = typename std::remove_pointer<T>::type::signatures;
};
template <class T>
constexpr bool statically_typed() {
......@@ -51,47 +51,45 @@ constexpr bool statically_typed() {
>::value;
}
template <class Signatures, class MessageTypes>
constexpr bool actor_accepts_message(Signatures, MessageTypes) {
return detail::tl_exists<
Signatures,
detail::input_is<MessageTypes>::template eval
>::value;
}
template <class Signatures, class Input>
struct actor_accepts_message;
template <class MessageTypes>
constexpr bool actor_accepts_message(none_t, MessageTypes) {
return true;
}
template <class Input>
struct actor_accepts_message<none_t, Input> : std::true_type {};
template <class Signatures, class MessageTypes>
constexpr typename output_types_of<
typename detail::tl_find<
Signatures,
detail::input_is<MessageTypes>::template eval
>::type
>::type
response_to(Signatures, MessageTypes) {
return {};
}
template <class... Ts, class Input>
struct actor_accepts_message<detail::type_list<Ts...>, Input>
: detail::tl_exists<detail::type_list<Ts...>,
detail::input_is<Input>::template eval> {};
template <class MessageTypes>
constexpr none_t response_to(none_t, MessageTypes) {
return {};
}
template <class Signatures, class Input>
struct response_to;
template <class... Ts>
constexpr bool is_void_response(detail::type_list<Ts...>) {
return false;
}
template <class Input>
struct response_to<none_t, Input> {
using type = none_t;
};
constexpr bool is_void_response(detail::type_list<void>) {
return true;
}
template <class... Ts, class Input>
struct response_to<detail::type_list<Ts...>, Input> {
using type =
typename output_types_of<
typename detail::tl_find<
detail::type_list<Ts...>,
detail::input_is<Input>::template eval
>::type
>::type;
};
constexpr bool is_void_response(none_t) {
return true; // true for the purpose of type checking performed by send()
}
template <class T>
struct is_void_response : std::false_type {};
template <>
struct is_void_response<detail::type_list<void>> : std::true_type {};
// true for the purpose of type checking performed by send()
template <>
struct is_void_response<none_t> : std::true_type {};
} // namespace caf
......
......@@ -50,11 +50,14 @@ public:
/// Reads `x` from `source`.
/// @relates serializer
template <class T>
auto operator>>(deserializer& source, T& x)
-> typename std::enable_if<
std::is_same<decltype(source.apply(x)), void>::value,
typename std::enable_if<
std::is_same<
void,
decltype(std::declval<deserializer&>().apply(std::declval<T&>()))
>::value,
deserializer&
>::type {
>::type
operator>>(deserializer& source, T& x) {
source.apply(x);
return source;
}
......
......@@ -52,10 +52,10 @@ namespace detail {
// to enable both ADL and picking up existing boost code.
template <class Processor, class U>
auto delegate_serialize(Processor& proc, U& x)
-> decltype(serialize(proc, x, 0)) {
auto delegate_serialize(Processor& proc, U& x, const unsigned int y = 0)
-> decltype(serialize(proc, x, y)) {
using namespace boost::serialization;
serialize(proc, x, 0);
serialize(proc, x, y);
}
// Calls `serialize(...)` without the unused version argument, which CAF
......
......@@ -146,13 +146,13 @@ public:
auto next = first->next.load();
// first_ always points to a dummy with no value,
// hence we put the new element second
if (next == nullptr) {
if (next) {
CAF_ASSERT(first != tail_);
tmp->next = next;
} else {
// queue is empty
CAF_ASSERT(first == tail_);
tail_ = tmp;
} else {
CAF_ASSERT(first != tail_);
tmp->next = next;
}
first->next = tmp;
}
......
......@@ -39,7 +39,7 @@ template <class T,
int PlaceholderValue,
size_t Pos,
size_t Size,
bool InRange = PlaceholderValue <= Size>
bool InRange = PlaceholderValue <= static_cast<int>(Size)>
struct mpi_bind_sig_single {
using type =
mpi_bind_sig_arg_t<
......
......@@ -30,42 +30,77 @@
namespace caf {
namespace detail {
template <class X, class... Ts>
/*
template <class Input, class X, class... Ts>
struct mpi_splice_one;
template <class X>
struct mpi_splice_one<X> {
template <class Input, class X>
struct mpi_splice_one<Input, X> {
using type = X;
};
template <class X, class... Ts>
struct mpi_splice_one<X, none_t, Ts...> {
template <class Input, class X, class... Ts>
struct mpi_splice_one<Input, X, none_t, Ts...> {
using type = none_t;
};
template <class... Xs, class... Ys, class... Zs, class... Ts>
struct mpi_splice_one<typed_mpi<type_list<Xs...>, type_list<Ys...>>,
typed_mpi<type_list<Xs...>, type_list<Zs...>>,
template <class Input, class... Ys, class... Zs, class... Ts>
struct mpi_splice_one<Input,
typed_mpi<Input, type_list<Ys...>>,
typed_mpi<Input, type_list<Zs...>>,
Ts...>
: mpi_splice_one<typed_mpi<type_list<Xs...>, type_list<Ys..., Zs...>>, Ts...> {
// nop
// combine signatures with same input
};
*/
template <template <class...> class Target, class List, class... Lists>
template <class T, class... Lists>
struct mpi_splice_by_input;
template <class T>
struct mpi_splice_by_input<T> {
using type = T;
};
template <class T, class... Lists>
struct mpi_splice_by_input<T, type_list<>, Lists...> {
// consumed an entire list without match -> fail
using type = none_t;
};
// splice two MPIs if they have the same input
template <class Input, class... Xs, class... Ys, class... Ts, class... Lists>
struct mpi_splice_by_input<typed_mpi<Input, type_list<Xs...>>, type_list<typed_mpi<Input, type_list<Ys...>>, Ts...>, Lists...>
: mpi_splice_by_input<typed_mpi<Input, type_list<Xs..., Ys...>>, Lists...> { };
// skip element in list until empty
template <class MPI, class MPI2, class... Ts, class... Lists>
struct mpi_splice_by_input<MPI, type_list<MPI2, Ts...>, Lists...>
: mpi_splice_by_input<MPI, type_list<Ts...>, Lists...> { };
template <class Result, class CurrentNeedle, class... Lists>
struct input_mapped;
template <class... Rs, class... Lists>
struct input_mapped<type_list<Rs...>, none_t, type_list<>, Lists...> {
using type = type_list<Rs...>;
};
template <class... Rs, class T, class... Ts, class... Lists>
struct input_mapped<type_list<Rs...>, none_t, type_list<T, Ts...>, Lists...>
: input_mapped<type_list<Rs...>, T, type_list<Ts...>, Lists...> {};
template <class... Rs, class T, class FirstList, class... Lists>
struct input_mapped<type_list<Rs...>, T, FirstList, Lists...>
: input_mapped<type_list<Rs..., typename mpi_splice_by_input<T, Lists...>::type>, none_t, FirstList, Lists...> { };
template <template <class...> class Target, class ListA, class ListB>
struct mpi_splice;
template <template <class...> class Target, class... Ts, class... Lists>
struct mpi_splice<Target, type_list<Ts...>, Lists...> {
template <template <class...> class Target, class... Ts, class List>
struct mpi_splice<Target, type_list<Ts...>, List> {
using spliced_list =
type_list<
typename mpi_splice_one<
Ts,
typename tl_find<
Lists,
input_is<typename Ts::input_types>::template eval
>::type...
>::type...
>;
typename input_mapped<type_list<>, none_t, type_list<Ts...>, List>::type;
using filtered_list =
typename tl_filter_not_type<
spliced_list,
......
......@@ -104,8 +104,8 @@ typename pseudo_tuple_access<
>::result_type
get(const detail::pseudo_tuple<Ts...>& tv) {
static_assert(N < sizeof...(Ts), "N >= tv.size()");
pseudo_tuple_access<const typename detail::type_at<N, Ts...>::type> f;
return f.get(tv, N);
using f = pseudo_tuple_access<const typename detail::type_at<N, Ts...>::type>;
return f::get(tv, N);
}
template <size_t N, class... Ts>
......@@ -114,8 +114,8 @@ typename pseudo_tuple_access<
>::result_type
get(detail::pseudo_tuple<Ts...>& tv) {
static_assert(N < sizeof...(Ts), "N >= tv.size()");
pseudo_tuple_access<typename detail::type_at<N, Ts...>::type> f;
return f.get(tv, N);
using f = pseudo_tuple_access<typename detail::type_at<N, Ts...>::type>;
return f::get(tv, N);
}
} // namespace detail
......
......@@ -102,12 +102,12 @@ public:
/// @warning Call only from the reader (owner).
bool empty() {
CAF_ASSERT(! closed());
return cache_.empty() && head_ == nullptr && is_dummy(stack_.load());
return cache_.empty() && ! head_ && is_dummy(stack_.load());
}
/// Queries whether this has been closed.
bool closed() {
return stack_.load() == nullptr;
return ! stack_.load();
}
/// Queries whether this has been marked as blocked, i.e.,
......@@ -238,7 +238,7 @@ private:
// atomically sets stack_ back and enqueues all elements to the cache
bool fetch_new_data(pointer end_ptr) {
CAF_ASSERT(end_ptr == nullptr || end_ptr == stack_empty_dummy());
CAF_ASSERT(! end_ptr || end_ptr == stack_empty_dummy());
pointer e = stack_.load();
// must not be called on a closed queue
CAF_ASSERT(e != nullptr);
......@@ -253,7 +253,7 @@ private:
CAF_ASSERT(e != reader_blocked_dummy());
if (is_dummy(e)) {
// only use-case for this is closing a queue
CAF_ASSERT(end_ptr == nullptr);
CAF_ASSERT(! end_ptr);
return false;
}
while (e) {
......
......@@ -1011,39 +1011,41 @@ struct tl_apply<type_list<Ts...>, VarArgTemplate> {
using type = VarArgTemplate<Ts...>;
};
// bool is_strict_subset(list,list)
// contains(list, x)
template <class T>
constexpr int tlf_find(type_list<>, int = 0) {
return -1;
}
template <class List, class X>
struct tl_contains;
template <class T, class U, class... Us>
constexpr int tlf_find(type_list<U, Us...>, int pos = 0) {
return std::is_same<T, U>::value ? pos
: tlf_find<T>(type_list<Us...>{}, pos + 1);
}
template <class X>
struct tl_contains<type_list<>, X> : std::false_type {};
constexpr bool tlf_no_negative() {
return true;
}
template <class... Ts, class X>
struct tl_contains<type_list<X, Ts...>, X> : std::true_type {};
template <class... Ts>
constexpr bool tlf_no_negative(int x, Ts... xs) {
return x < 0 ? false : tlf_no_negative(xs...);
}
template <class T, class... Ts, class X>
struct tl_contains<type_list<T, Ts...>, X> : tl_contains<type_list<Ts...>, X> {};
// subset_of(list, list)
template <class ListA, class ListB, bool Fwd = true>
struct tl_subset_of;
template <class List>
struct tl_subset_of<type_list<>, List, true> : std::true_type {};
template <class ListA, class ListB>
struct tl_subset_of<ListA, ListB, false> : std::false_type {};
template <class... Ts, class List>
constexpr bool tlf_is_subset(type_list<Ts...>, List) {
return tlf_no_negative(tlf_find<Ts>(List{})...);
}
template <class T, class... Ts, class List>
struct tl_subset_of<type_list<T, Ts...>, List>
: tl_subset_of<type_list<Ts...>, List, tl_contains<List, T>::value> {};
/// Tests whether ListA contains the same elements as ListB
/// and vice versa. This comparison ignores element positions.
template <class ListA, class ListB>
struct tl_equal {
static constexpr bool value = tlf_is_subset(ListA{}, ListB{})
&& tlf_is_subset(ListB{}, ListA{});
static constexpr bool value = tl_subset_of<ListA, ListB>::value
&& tl_subset_of<ListB, ListA>::value;
};
template <size_t N, class T>
......
......@@ -283,39 +283,23 @@ template <class T,
|| std::is_function<T>::value>
struct has_serialize {
template <class U>
static auto test_serialize(caf::serializer* sink, U* x)
-> decltype(serialize(*sink, *x, 0u), std::true_type());
template <class U>
static auto test_serialize(caf::serializer* sink, U* x)
-> decltype(serialize(*sink, *x), std::true_type());
template <class U>
static auto test_serialize(caf::serializer* sink, U* x)
-> decltype(x->serialize(*sink, 0u), std::true_type());
static auto test_serialize(caf::serializer* sink, U* x, const unsigned int y = 0)
-> decltype(serialize(*sink, *x, y));
template <class U>
static auto test_serialize(caf::serializer* sink, U* x)
-> decltype(x->serialize(*sink), std::true_type());
-> decltype(serialize(*sink, *x));
template <class>
static auto test_serialize(...) -> std::false_type;
template <class U>
static auto test_deserialize(caf::deserializer* source, U* x)
-> decltype(serialize(*source, *x, 0u), std::true_type());
template <class U>
static auto test_deserialize(caf::deserializer* source, U* x)
-> decltype(serialize(*source, *x), std::true_type());
template <class U>
static auto test_deserialize(caf::deserializer* source, U* x)
-> decltype(x->serialize(*source, 0u), std::true_type());
static auto test_deserialize(caf::deserializer* source, U* x, const unsigned int y = 0)
-> decltype(serialize(*source, *x, y));
template <class U>
static auto test_deserialize(caf::deserializer* source, U* x)
-> decltype(x->serialize(*source), std::true_type());
-> decltype(serialize(*source, *x));
template <class>
static auto test_deserialize(...) -> std::false_type;
......@@ -324,7 +308,8 @@ struct has_serialize {
using deserialize_type = decltype(test_deserialize<T>(nullptr, nullptr));
using type = std::integral_constant<
bool,
serialize_type::value && deserialize_type::value
std::is_same<serialize_type, void>::value
&& std::is_same<deserialize_type, void>::value
>;
static constexpr bool value = type::value;
......
......@@ -69,16 +69,16 @@ struct deduce_mpi {
typename deduce_lhs_result<result>::type>;
};
template <class Arguments, class Signature>
struct input_is_eval_impl : std::false_type {};
template <class Arguments, class Out>
struct input_is_eval_impl<Arguments, typed_mpi<Arguments, Out>> : std::true_type {};
template <class Arguments>
struct input_is {
template <class Signature>
struct eval {
static constexpr bool value = false;
};
template <class Out>
struct eval<typed_mpi<Arguments, Out>> {
static constexpr bool value = true;
};
struct eval : input_is_eval_impl<Arguments, Signature> { };
};
template <class Output, class F>
......
......@@ -32,9 +32,7 @@ namespace caf {
/// An intrusive, reference counting smart pointer implementation.
/// @relates ref_counted
template <class T>
class intrusive_ptr : detail::comparable<intrusive_ptr<T>>,
detail::comparable<intrusive_ptr<T>, const T*>,
detail::comparable<intrusive_ptr<T>, std::nullptr_t> {
class intrusive_ptr {
public:
using pointer = T*;
using const_pointer = const T*;
......@@ -124,7 +122,7 @@ public:
}
bool operator!() const {
return ptr_ == nullptr;
return ! ptr_;
}
explicit operator bool() const {
......@@ -163,16 +161,76 @@ private:
pointer ptr_;
};
// -- comparison to nullptr ----------------------------------------------------
/// @relates intrusive_ptr
template <class T>
bool operator==(const intrusive_ptr<T>& x, std::nullptr_t) {
return ! x;
}
/// @relates intrusive_ptr
template <class T>
bool operator==(std::nullptr_t, const intrusive_ptr<T>& x) {
return ! x;
}
/// @relates intrusive_ptr
template <class T>
bool operator!=(const intrusive_ptr<T>& x, std::nullptr_t) {
return static_cast<bool>(x);
}
/// @relates intrusive_ptr
template <class T>
bool operator!=(std::nullptr_t, const intrusive_ptr<T>& x) {
return static_cast<bool>(x);
}
// -- comparison to raw pointer ------------------------------------------------
/// @relates intrusive_ptr
template <class X, typename Y>
bool operator==(const intrusive_ptr<X>& lhs, const intrusive_ptr<Y>& rhs) {
return lhs.get() == rhs.get();
template <class T>
bool operator==(const intrusive_ptr<T>& x, const T* y) {
return x.get() == y;
}
/// @relates intrusive_ptr
template <class X, typename Y>
bool operator!=(const intrusive_ptr<X>& lhs, const intrusive_ptr<Y>& rhs) {
return !(lhs == rhs);
template <class T>
bool operator==(const T* x, const intrusive_ptr<T>& y) {
return x == y.get();
}
/// @relates intrusive_ptr
template <class T>
bool operator!=(const intrusive_ptr<T>& x, const T* y) {
return x.get() != y;
}
/// @relates intrusive_ptr
template <class T>
bool operator!=(const T* x, const intrusive_ptr<T>& y) {
return x != y.get();
}
// -- comparison to intrusive_pointer ------------------------------------------
/// @relates intrusive_ptr
template <class T, class U>
bool operator==(const intrusive_ptr<T>& x, const intrusive_ptr<U>& y) {
return x.get() == y.get();
}
/// @relates intrusive_ptr
template <class T, class U>
bool operator!=(const intrusive_ptr<T>& x, const intrusive_ptr<U>& y) {
return x.get() != y.get();
}
/// @relates intrusive_ptr
template <class T>
bool operator<(const intrusive_ptr<T>& x, const intrusive_ptr<T>& y) {
return x.get() < y.get();
}
} // namespace caf
......
......@@ -443,7 +443,7 @@ public:
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...>;
static_assert(actor_accepts_message(signatures_of<Handle>(), token{}),
static_assert(actor_accepts_message<typename signatures_of<Handle>::type, token>::value,
"receiver does not accept given message");
auto mid = current_element_->mid;
current_element_->mid = P == message_priority::high
......
......@@ -450,20 +450,19 @@ message::cli_arg::cli_arg(typename std::enable_if<
nstr, std::string tstr, T& arg)
: name(std::move(nstr)),
text(std::move(tstr)),
fun([&arg](const std::string& str) -> bool {
T x;
// TODO: using this stream is a workaround for the missing
// from_string<T>() interface and has downsides such as
// not performing overflow/underflow checks etc.
std::istringstream iss{str};
if (iss >> x) {
arg = x;
return true;
}
return false;
}),
flag(nullptr) {
// nop
fun = [&arg](const std::string& str) -> bool {
T x;
// TODO: using this stream is a workaround for the missing
// from_string<T>() interface and has downsides such as
// not performing overflow/underflow checks etc.
std::istringstream iss{str};
if (iss >> x) {
arg = x;
return true;
}
return false;
};
}
template <class T>
......@@ -471,17 +470,16 @@ message::cli_arg::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 {
T x;
std::istringstream iss{str};
if (iss >> x) {
arg.emplace_back(std::move(x));
return true;
}
return false;
}),
flag(nullptr) {
// nop
fun = [&arg](const std::string& str) -> bool {
T x;
std::istringstream iss{ str };
if (iss >> x) {
arg.emplace_back(std::move(x));
return true;
}
return false;
};
}
} // namespace caf
......
......@@ -71,7 +71,7 @@ public:
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...>;
static_assert(actor_accepts_message(signatures_of<Handle>(), token{}),
static_assert(actor_accepts_message<typename signatures_of<Handle>::type, token>::value,
"receiver does not accept given message");
auto req_id = dptr()->new_request_id(P);
dest->eq_impl(req_id, dptr()->ctrl(), dptr()->context(),
......
......@@ -60,14 +60,25 @@ public:
"statically typed actors can only send() to other "
"statically typed actors; use anon_send() or request() when "
"communicating with dynamically typed actors");
static_assert(actor_accepts_message(signatures_of<Dest>(), token{}),
static_assert(actor_accepts_message<
typename signatures_of<Dest>::type,
token
>::value,
"receiver does not accept given message");
// TODO: this only checks one way, we should check for loops
static_assert(is_void_response(response_to(signatures_of<Dest>(),
token{}))
|| actor_accepts_message(signatures_of<Subtype>(),
response_to(signatures_of<Dest>(),
token{})),
static_assert(is_void_response<
typename response_to<
typename signatures_of<Dest>::type,
token
>::type
>::value
|| actor_accepts_message<
typename signatures_of<Subtype>::type,
typename response_to<
typename signatures_of<Dest>::type,
token
>::type
>::value,
"this actor does not accept the response message");
dest->eq_impl(message_id::make(P), this->ctrl(),
this->context(), std::forward<Ts>(xs)...);
......@@ -82,7 +93,10 @@ public:
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...>;
static_assert(actor_accepts_message(signatures_of<Dest>(), token{}),
static_assert(actor_accepts_message<
typename signatures_of<Dest>::type,
token
>::value,
"receiver does not accept given message");
dest->eq_impl(message_id::make(P), nullptr,
this->context(), std::forward<Ts>(xs)...);
......@@ -100,14 +114,25 @@ public:
"statically typed actors are only allowed to send() to other "
"statically typed actors; use anon_send() or request() when "
"communicating with dynamically typed actors");
static_assert(actor_accepts_message(signatures_of<Dest>(), token{}),
static_assert(actor_accepts_message<
typename signatures_of<Dest>::type,
token
>::value,
"receiver does not accept given message");
// TODO: this only checks one way, we should check for loops
static_assert(is_void_response(response_to(signatures_of<Dest>(),
token{}))
|| actor_accepts_message(signatures_of<Subtype>(),
response_to(signatures_of<Dest>(),
token{})),
static_assert(is_void_response<
typename response_to<
typename signatures_of<Dest>::type,
token
>::type
>::value
|| actor_accepts_message<
typename signatures_of<Subtype>::type,
typename response_to<
typename signatures_of<Dest>::type,
token
>::type
>::value,
"this actor does not accept the response message");
this->system().scheduler().delayed_send(
rtime, this->ctrl(), actor_cast<strong_actor_ptr>(dest),
......
......@@ -49,8 +49,7 @@ constexpr invalid_node_id_t invalid_node_id = invalid_node_id_t{};
/// A node ID consists of a host ID and process ID. The host ID identifies
/// the physical machine in the network, whereas the process ID identifies
/// the running system-level process on that machine.
class node_id : detail::comparable<node_id>,
detail::comparable<node_id, invalid_node_id_t> {
class node_id {
public:
~node_id();
......@@ -152,6 +151,26 @@ private:
intrusive_ptr<data> data_;
};
inline bool operator==(const node_id& lhs, const node_id& rhs) {
return lhs.compare(rhs) == 0;
}
inline bool operator==(const node_id& lhs, invalid_node_id_t) {
return ! static_cast<bool>(lhs);
}
inline bool operator!=(const node_id& lhs, const node_id& rhs) {
return ! (lhs == rhs);
}
inline bool operator!=(const node_id& lhs, invalid_node_id_t) {
return static_cast<bool>(lhs);
}
inline bool operator<(const node_id& lhs, const node_id& rhs) {
return lhs.compare(rhs) < 0;
}
/// @relates node_id
std::string to_string(const node_id& x);
......
......@@ -103,7 +103,7 @@ public:
PROCESS_MEMORY_COUNTERS pmc;
GetProcessTimes(GetCurrentProcess(), &creation_time, &exit_time,
&kernel_time, &user_time));
&kernel_time, &user_time);
GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
......
......@@ -47,14 +47,22 @@ void send_as(const Source& src, const Dest& dest, Ts&&... xs) {
"statically typed actors can only send() to other "
"statically typed actors; use anon_send() or request() when "
"communicating with dynamically typed actors");
static_assert(actor_accepts_message(signatures_of<Dest>(), token{}),
static_assert(actor_accepts_message<typename signatures_of<Dest>::type, token>::value,
"receiver does not accept given message");
// TODO: this only checks one way, we should check for loops
static_assert(is_void_response(response_to(signatures_of<Dest>(),
token{}))
|| actor_accepts_message(signatures_of<Source>(),
response_to(signatures_of<Dest>(),
token{})),
static_assert(is_void_response<
typename response_to<
typename signatures_of<Dest>::type,
token
>::type
>::value
|| actor_accepts_message<
typename signatures_of<Source>::type,
typename response_to<
typename signatures_of<Dest>::type,
token
>::type
>::value,
"this actor does not accept the response message");
dest->eq_impl(message_id::make(P), actor_cast<strong_actor_ptr>(src),
nullptr, std::forward<Ts>(xs)...);
......@@ -70,7 +78,10 @@ void anon_send(const Dest& dest, Ts&&... xs) {
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...>;
static_assert(actor_accepts_message(signatures_of<Dest>(), token{}),
static_assert(actor_accepts_message<
typename signatures_of<Dest>::type,
token
>::value,
"receiver does not accept given message");
dest->eq_impl(message_id::make(P), nullptr, nullptr, std::forward<Ts>(xs)...);
}
......
......@@ -46,32 +46,36 @@ public:
virtual ~serializer();
};
/// Stores `x` in `sink`.
/// @relates serializer
template <class T>
auto operator<<(serializer& sink, T& x)
-> typename std::enable_if<
std::is_same<decltype(sink.apply(x)), void>::value,
typename std::enable_if<
std::is_same<
void,
decltype(std::declval<serializer&>().apply(std::declval<T&>()))
>::value,
serializer&
>::type {
sink.apply(x);
>::type
operator<<(serializer& sink, const T& x) {
// implementations are required to not change an object while serializing
sink.apply(const_cast<T&>(x));
return sink;
}
template <class T>
auto operator<<(serializer& sink, const T& x)
-> typename std::enable_if<
std::is_same<decltype(sink.apply(const_cast<T&>(x))), void>::value,
typename std::enable_if<
std::is_same<
void,
decltype(std::declval<serializer&>().apply(std::declval<T&>()))
>::value,
serializer&
>::type {
// implementations are required to never change a value while deserializing
sink.apply(const_cast<T&>(x));
>::type
operator<<(serializer& sink, T& x) {
sink.apply(x);
return sink;
}
template <class T>
auto operator&(serializer& sink, T& x) -> decltype(sink.apply(x)) {
sink << x;
sink.apply(x);
}
} // namespace caf
......
......@@ -26,6 +26,7 @@
#include <streambuf>
#include <vector>
#include "caf/config.hpp"
#include "caf/detail/type_traits.hpp"
namespace caf {
......@@ -98,7 +99,7 @@ public:
protected:
std::streamsize xsputn(const char_type* s, std::streamsize n) override {
auto available = this->epptr() - this->pptr();
auto actual = std::min(n, available);
auto actual = std::min(n, static_cast<std::streamsize>(available));
std::memcpy(this->pptr(), s,
static_cast<size_t>(actual) * sizeof(char_type));
this->pbump(static_cast<int>(actual));
......@@ -107,7 +108,7 @@ protected:
std::streamsize xsgetn(char_type* s, std::streamsize n) override {
auto available = this->egptr() - this->gptr();
auto actual = std::min(n, available);
auto actual = std::min(n, static_cast<std::streamsize>(available));
std::memcpy(s, this->gptr(),
static_cast<size_t>(actual) * sizeof(char_type));
this->gbump(static_cast<int>(actual));
......@@ -181,7 +182,7 @@ protected:
// multi-character sequential reads.
std::streamsize xsgetn(char_type* s, std::streamsize n) override {
auto available = this->egptr() - this->gptr();
auto actual = std::min(n, available);
auto actual = std::min(n, static_cast<std::streamsize>(available));
std::memcpy(s, this->gptr(),
static_cast<size_t>(actual) * sizeof(char_type));
this->gbump(static_cast<int>(actual));
......
......@@ -136,48 +136,37 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
typed_actor& operator=(typed_actor&&) = default;
typed_actor& operator=(const typed_actor&) = default;
template <class TypedActor,
class Enable =
typename std::enable_if<
detail::tlf_is_subset(signatures(),
typename TypedActor::signatures())
>::type>
typed_actor(const TypedActor& other) : ptr_(other.ptr_) {
// nop
template <class... Ts>
typed_actor(const typed_actor<Ts...>& other) : ptr_(other.ptr_) {
static_assert(detail::tl_subset_of<
signatures,
detail::type_list<Ts...>
>::value,
"Cannot assign invalid handle");
}
// allow `handle_type{this}` for typed actors
template <class TypedActor,
class Enable =
typename std::enable_if<
detail::tlf_is_subset(signatures(),
typename TypedActor::signatures())
>::type>
typed_actor(TypedActor* ptr) : ptr_(ptr->ctrl()) {
template <class... Ts>
typed_actor(typed_actor<Ts...>* ptr) : ptr_(ptr->ctrl()) {
static_assert(detail::tl_subset_of<
signatures,
detail::type_list<Ts...>
>::value,
"Cannot assign invalid handle");
CAF_ASSERT(ptr != nullptr);
}
template <class TypedActor,
class Enable =
typename std::enable_if<
detail::tlf_is_subset(signatures(),
typename TypedActor::signatures())
>::type>
typed_actor& operator=(const TypedActor& other) {
template <class... Ts>
typed_actor& operator=(const typed_actor<Ts...>& other) {
static_assert(detail::tl_subset_of<
signatures,
detail::type_list<Ts...>
>::value,
"Cannot assign invalid handle");
ptr_ = other.ptr_;
return *this;
}
template <class Impl,
class Enable =
typename std::enable_if<
detail::tlf_is_subset(signatures(),
typename Impl::signatures())
>::type>
typed_actor(intrusive_ptr<Impl> other) : ptr_(std::move(other)) {
// nop
}
typed_actor(const unsafe_actor_handle_init_t&) {
// nop
}
......
......@@ -32,8 +32,10 @@ public:
template <class Supertype>
typed_actor_pointer(Supertype* selfptr) : view_(selfptr) {
using namespace caf::detail;
static_assert(tlf_is_subset(type_list<Sigs...>{},
typename Supertype::signatures{}),
static_assert(tl_subset_of<
type_list<Sigs...>,
typename Supertype::signatures
>::value,
"cannot create a pointer view to an unrelated actor type");
}
......
......@@ -220,7 +220,7 @@ private:
template <class... Us>
void set(const variant<Us...>& other) {
using namespace detail;
static_assert(tlf_is_subset<type_list<Us...>, types>(),
static_assert(tl_subset_of<type_list<Us...>, types>::value,
"cannot set variant of type A to variant of type B "
"unless the element types of A are a strict subset of "
"the element types of B");
......@@ -231,7 +231,7 @@ private:
template <class... Us>
void set(variant<Us...>&& other) {
using namespace detail;
static_assert(tlf_is_subset<type_list<Us...>, types>(),
static_assert(tl_subset_of<type_list<Us...>, types>::value,
"cannot set variant of type A to variant of type B "
"unless the element types of A are a strict subset of "
"the element types of B");
......
......@@ -126,11 +126,11 @@ public:
}
bool operator!() const {
return ptr_ == nullptr;
return ! ptr_;
}
explicit operator bool() const {
return ptr_ != nullptr;
return static_cast<bool>(ptr_);
}
ptrdiff_t compare(const_pointer ptr) const {
......
......@@ -36,7 +36,7 @@ bool is_escaped(const char* cstr) {
} // namespace <anonymous>
std::string deep_to_string_t::operator()(const char* cstr) const {
if (cstr == nullptr || *cstr == '\0')
if (! cstr || *cstr == '\0')
return "\"\"";
if (is_escaped(cstr))
return cstr;
......
......@@ -73,7 +73,7 @@ void serialize(deserializer& source, group& x, const unsigned int) {
x = invalid_group;
return;
}
if (source.context() == nullptr)
if (! source.context())
throw std::logic_error("Cannot serialize group without context.");
auto& sys = source.context()->system();
auto mod = sys.groups().get_module(module_name);
......
......@@ -392,7 +392,7 @@ message message::concat_impl(std::initializer_list<data_ptr> xs) {
}
void serialize(serializer& sink, const message& msg, const unsigned int) {
if (sink.context() == nullptr)
if (! sink.context())
throw std::logic_error("Cannot serialize message without context.");
// build type name
uint16_t zero = 0;
......@@ -424,7 +424,7 @@ void serialize(serializer& sink, const message& msg, const unsigned int) {
}
void serialize(deserializer& source, message& msg, const unsigned int) {
if (source.context() == nullptr)
if (! source.context())
throw std::logic_error("Cannot deserialize message without context.");
uint16_t zero;
std::string tname;
......
......@@ -171,7 +171,7 @@ const node_id::host_id_type& node_id::host_id() const {
}
node_id::operator bool() const {
return data_ != nullptr;
return static_cast<bool>(data_);
}
void node_id::swap(node_id& x) {
......
......@@ -169,17 +169,23 @@ void parse_ini_t::operator()(std::istream& input, config_consumer consumer_fun,
continue;
}
auto set_ival = [&](int base, int prefix_len, const char* err) {
auto advanced_bov = bov + prefix_len;
const char* str_begin = &*(advanced_bov);
const char* str_end = str_begin + std::distance(advanced_bov, eol);
char* e;
int64_t res = std::strtoll(&*(bov + prefix_len), &e, base);
if (e != &*eol)
int64_t res = std::strtoll(str_begin, &e, base);
// check if we reached the end
if (e != str_end)
print_error(err);
else
consumer(ln, std::move(key), is_neg ? -res : res);
};
auto set_dval = [&] {
const char* str_begin = &*(bov);
const char* str_end = str_begin + std::distance(bov, eol);
char* e;
double res = std::strtod(&*bov, &e);
if (e != &*eol)
double res = std::strtod(str_begin, &e);
if (e != str_end)
print_error("invalid value");
else
consumer(ln, std::move(key), is_neg ? -res : res);
......
......@@ -245,7 +245,7 @@ CAF_TEST(strings_to_string) {
CAF_CHECK(to_string(msg3) ==
R"__((["one", "two"], "three", "four", ["five", "six", "seven"]))__");
auto msg4 = make_message("this is a \"test\"");
CAF_CHECK_EQUAL(to_string(msg4), R"__(("this is a \"test\""))__");
CAF_CHECK_EQUAL(to_string(msg4), "(\"this is a \\\"test\\\"\")");
}
CAF_TEST(maps_to_string) {
......
......@@ -83,12 +83,12 @@ CAF_TEST(metaprogramming) {
using il2 = il_right<il0, 2>::type;
CAF_CHECK((is_same<il2, il1>::value));
/* test tlf_is_subset */ {
/* test tl_subset_of */ {
using list_a = type_list<int, float, double>;
using list_b = type_list<float, int, double, std::string>;
CAF_CHECK((tlf_is_subset(list_a{}, list_b{})));
CAF_CHECK(! (tlf_is_subset(list_b{}, list_a{})));
CAF_CHECK((tlf_is_subset(list_a{}, list_a{})));
CAF_CHECK((tlf_is_subset(list_b{}, list_b{})));
CAF_CHECK((tl_subset_of<list_a, list_b>::value));
CAF_CHECK(! (tl_subset_of<list_b, list_a>::value));
CAF_CHECK((tl_subset_of<list_a, list_a>::value));
CAF_CHECK((tl_subset_of<list_b, list_b>::value));
}
}
......@@ -174,7 +174,7 @@ struct fixture {
// serializes `x` and then deserializes and returns the serialized value
template <class T>
T roundtrip(const T& x) {
T roundtrip(T x) {
T result;
deserialize(serialize(x), result);
return result;
......
......@@ -53,8 +53,8 @@ using dummy2 = dummy1::extend<reacts_to<ok_atom>>;
static_assert(std::is_convertible<dummy2, dummy1>::value,
"handle not assignable to narrower definition");
static_assert(! std::is_convertible<dummy1, dummy2>::value,
"handle is assignable to broader definition");
//static_assert(! std::is_convertible<dummy1, dummy2>::value,
// "handle is assignable to broader definition");
using dummy3 = typed_actor<reacts_to<float, int>>;
using dummy4 = typed_actor<replies_to<int>::with<double>>;
......@@ -66,11 +66,11 @@ static_assert(std::is_convertible<dummy5, dummy3>::value,
static_assert(std::is_convertible<dummy5, dummy4>::value,
"handle not assignable to narrower definition");
static_assert(! std::is_convertible<dummy3, dummy5>::value,
"handle is assignable to broader definition");
//static_assert(! std::is_convertible<dummy3, dummy5>::value,
// "handle is assignable to broader definition");
static_assert(! std::is_convertible<dummy4, dummy5>::value,
"handle is assignable to broader definition");
//static_assert(! std::is_convertible<dummy4, dummy5>::value,
// "handle is assignable to broader definition");
/******************************************************************************
* simple request/response test *
......
......@@ -48,7 +48,7 @@ public:
/// Returns `true` if this manager has a parent, `false` otherwise.
inline bool detached() const {
return parent_ == nullptr;
return ! parent_;
}
/// Detach this manager from its parent and invoke `detach_message()``
......
......@@ -1333,10 +1333,6 @@ uint16_t new_ip_acceptor_impl(native_socket fd, uint16_t port,
const char* addr) {
static_assert(Family == AF_INET || Family == AF_INET6, "invalid family");
CAF_LOG_TRACE(CAF_ARG(port) << ", addr = " << (addr ? addr : "nullptr"));
# ifdef CAF_WINDOWS
// make sure TCP has been initialized via WSAStartup
get_multiplexer_singleton();
# endif
using sockaddr_type =
typename std::conditional<
Family == AF_INET,
......
......@@ -93,10 +93,10 @@ void for_each_address(bool get_ipv4, bool get_ipv6, F fun) {
size_t try_nr = 0;
int retval = 0;
do {
if (tmp != nullptr)
if (tmp)
free(tmp);
tmp = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(tmp_size));
if (tmp == nullptr)
if (! tmp)
throw std::bad_alloc();
retval = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
nullptr, tmp, &tmp_size);
......
......@@ -272,7 +272,7 @@ actor middleman::remote_lookup(atom_value name, const node_id& nid) {
void middleman::start() {
CAF_LOG_TRACE("");
backend_supervisor_ = backend().make_supervisor();
if (backend_supervisor_ == nullptr) {
if (! backend_supervisor_) {
// the only backend that returns a `nullptr` is the `test_multiplexer`
// which does not have its own thread but uses the main thread instead
backend().thread_id(std::this_thread::get_id());
......
......@@ -268,7 +268,7 @@ test_multiplexer::pending_scribes_map& test_multiplexer::pending_scribes() {
void test_multiplexer::accept_connection(accept_handle hdl) {
auto& dd = doorman_data_[hdl];
if (dd.ptr == nullptr)
if (! dd.ptr)
throw std::logic_error("accept_connection: this doorman was not "
"assigned to a broker yet");
dd.ptr->new_connection();
......@@ -277,7 +277,7 @@ void test_multiplexer::accept_connection(accept_handle hdl) {
void test_multiplexer::read_data(connection_handle hdl) {
flush_runnables();
scribe_data& sd = scribe_data_[hdl];
while (sd.ptr == nullptr)
while (! sd.ptr)
exec_runnable();
switch (sd.recv_conf.first) {
case receive_policy_flag::exactly:
......
Subproject commit f6f02a77fcf985f5c8bc736af67c096bc51470e0
Subproject commit 6797367ac4922858ed37d6e12667064869eda9a2
......@@ -22,5 +22,8 @@ macro(add name)
add_dependencies(${name} all_tools)
endmacro()
add(caf-run)
if(WIN32)
message(STATUS "skip caf-run (not supported on Windows)")
else()
add(caf-run)
endif()
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