Commit 18bcf49c authored by Dominik Charousset's avatar Dominik Charousset

Implement new syntax for atom constants

parent 7b9905de
...@@ -47,11 +47,27 @@ constexpr atom_value atom(char const (&str)[Size]) { ...@@ -47,11 +47,27 @@ constexpr atom_value atom(char const (&str)[Size]) {
} }
/** /**
* Type alias for treating atom constants at compile-time * Lifts an `atom_value` to a compile-time constant.
* (cf. "Int-ToType" idiom).
*/ */
template <atom_value Value> template <atom_value V>
using atom_constant = std::integral_constant<atom_value, Value>; struct atom_constant {
constexpr atom_constant() {
// nop
}
/**
* Returns the wrapped value.
*/
constexpr operator atom_value() const {
return V;
}
/**
* Returns an instance *of this constant* (*not* an `atom_value`).
*/
static const atom_constant value;
};
template <atom_value V>
const atom_constant<V> atom_constant<V>::value = atom_constant<V>{};
/** /**
* Generic 'GET' atom for request operations. * Generic 'GET' atom for request operations.
......
...@@ -35,8 +35,25 @@ namespace detail { ...@@ -35,8 +35,25 @@ namespace detail {
template <class A, class B> template <class A, class B>
struct ctm_cmp : std::false_type { }; struct ctm_cmp : std::false_type { };
template <class T> template <class In, class L, class R1, class R2>
struct ctm_cmp<T, T> : std::true_type { }; struct ctm_cmp<typed_mpi<In, L, R1>,
typed_mpi<In, L, R2>> {
static constexpr bool value = std::is_same<R1, R2>::value
|| std::is_same<R2, empty_type_list>::value;
};
/*
template <class In, class Out>
struct ctm_cmp<typed_mpi<In, Out, empty_type_list>,
typed_mpi<In, Out, empty_type_list>>
: std::true_type { };
template <class In, class L, class R>
struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, L, R>>
: std::true_type { };
*/
template <class In, class Out> template <class In, class Out>
struct ctm_cmp<typed_mpi<In, Out, empty_type_list>, struct ctm_cmp<typed_mpi<In, Out, empty_type_list>,
...@@ -58,6 +75,18 @@ struct ctm_cmp<typed_mpi<In, L, R>, ...@@ -58,6 +75,18 @@ struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, type_list<typed_response_promise<either_or_t<L, R>>>, empty_type_list>> typed_mpi<In, type_list<typed_response_promise<either_or_t<L, R>>>, empty_type_list>>
: std::true_type { }; : std::true_type { };
/*
template <class In, class L, class R>
struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, L, empty_type_list>>
: std::true_type { };
*/
template <class In, class L, class R>
struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, R, empty_type_list>>
: std::true_type { };
template <class A, class B> template <class A, class B>
struct ctm : std::false_type { }; struct ctm : std::false_type { };
......
...@@ -148,10 +148,15 @@ class lifted_fun_invoker<bool, F> { ...@@ -148,10 +148,15 @@ class lifted_fun_invoker<bool, F> {
*/ */
template <class F, class ListOfProjections, class... Args> template <class F, class ListOfProjections, class... Args>
class lifted_fun { class lifted_fun {
public: public:
using plain_result_type = typename get_callable_trait<F>::result_type;
using result_type = typename get_callable_trait<F>::result_type; using result_type =
typename std::conditional<
std::is_reference<plain_result_type>::value,
plain_result_type,
typename std::remove_const<plain_result_type>::type
>::type;
// Let F be "R (Ts...)" then lifted_fun<F...> returns optional<R> // Let F be "R (Ts...)" then lifted_fun<F...> returns optional<R>
// unless R is void in which case bool is returned // unless R is void in which case bool is returned
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <numeric> #include <numeric>
#include <typeinfo> #include <typeinfo>
#include "caf/atom.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/wildcard_position.hpp" #include "caf/wildcard_position.hpp"
...@@ -33,56 +34,37 @@ ...@@ -33,56 +34,37 @@
namespace caf { namespace caf {
namespace detail { namespace detail {
bool match_element(const std::type_info* type, const message_iterator& iter, bool match_element(const atom_value&, const std::type_info* type,
void** storage); const message_iterator& iter, void** storage);
template <class T> bool match_atom_constant(const atom_value&, const std::type_info* type,
bool match_integral_constant_element(const std::type_info* type, const message_iterator& iter, void** storage);
const message_iterator& iter,
void** storage) {
auto value = T::value;
auto uti = iter.type();
if (!uti->equal_to(*type) || !uti->equals(iter.value(), &value)) {
return false;
}
if (storage) {
// This assignment implicitly casts `T*` to `integral_constant<T, V>*`.
// This type violation could theoretically cause undefined behavior.
// However, `T::value` does have an address that is guaranteed to be valid
// throughout the runtime of the program and the integral constant
// objects does not have any members. Hence, this is nonetheless safe.
auto ptr = reinterpret_cast<const void*>(&T::value);
// Again, this const cast is always safe because we will never derefence
// this pointer since `integral_constant<T, V>` has no members.
*storage = const_cast<void*>(ptr);
}
return true;
}
struct meta_element { struct meta_element {
atom_value v;
const std::type_info* type; const std::type_info* type;
bool (*fun)(const std::type_info*, const message_iterator&, void**); bool (*fun)(const atom_value&, const std::type_info*,
const message_iterator&, void**);
}; };
template <class T> template <class T>
struct meta_element_factory { struct meta_element_factory {
static meta_element create() { static meta_element create() {
return {&typeid(T), match_element}; return {static_cast<atom_value>(0), &typeid(T), match_element};
} }
}; };
template <class T, T V> template <atom_value V>
struct meta_element_factory<std::integral_constant<T, V>> { struct meta_element_factory<atom_constant<V>> {
static meta_element create() { static meta_element create() {
return {&typeid(T), return {V, &typeid(atom_value), match_atom_constant};
match_integral_constant_element<std::integral_constant<T, V>>};
} }
}; };
template <> template <>
struct meta_element_factory<anything> { struct meta_element_factory<anything> {
static meta_element create() { static meta_element create() {
return {nullptr, nullptr}; return {static_cast<atom_value>(0), nullptr, nullptr};
} }
}; };
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <type_traits> #include <type_traits>
#include "caf/atom.hpp"
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/detail/int_list.hpp" #include "caf/detail/int_list.hpp"
...@@ -282,13 +283,13 @@ inline bool operator!=(const message& lhs, const message& rhs) { ...@@ -282,13 +283,13 @@ inline bool operator!=(const message& lhs, const message& rhs) {
} }
template <class T> template <class T>
struct lift_message_element { struct unbox_message_element {
using type = T; using type = T;
}; };
template <class T, T V> template <atom_value V>
struct lift_message_element<std::integral_constant<T, V>> { struct unbox_message_element<atom_constant<V>> {
using type = T; using type = atom_value;
}; };
/** /**
...@@ -303,10 +304,10 @@ typename std::enable_if< ...@@ -303,10 +304,10 @@ typename std::enable_if<
>::type >::type
make_message(T&& arg, Ts&&... args) { make_message(T&& arg, Ts&&... args) {
using storage using storage
= detail::tuple_vals<typename lift_message_element< = detail::tuple_vals<typename unbox_message_element<
typename detail::strip_and_convert<T>::type typename detail::strip_and_convert<T>::type
>::type, >::type,
typename lift_message_element< typename unbox_message_element<
typename detail::strip_and_convert<Ts>::type typename detail::strip_and_convert<Ts>::type
>::type...>; >::type...>;
auto ptr = new storage(std::forward<T>(arg), std::forward<Ts>(args)...); auto ptr = new storage(std::forward<T>(arg), std::forward<Ts>(args)...);
......
...@@ -28,8 +28,8 @@ bool is_wildcard(const meta_element& me) { ...@@ -28,8 +28,8 @@ bool is_wildcard(const meta_element& me) {
return me.type == nullptr; return me.type == nullptr;
} }
bool match_element(const std::type_info* type, const message_iterator& iter, bool match_element(const atom_value&, const std::type_info* type,
void** storage) { const message_iterator& iter, void** storage) {
if (!iter.type()->equal_to(*type)) { if (!iter.type()->equal_to(*type)) {
return false; return false;
} }
...@@ -39,6 +39,27 @@ bool match_element(const std::type_info* type, const message_iterator& iter, ...@@ -39,6 +39,27 @@ bool match_element(const std::type_info* type, const message_iterator& iter,
return true; 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)) {
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));
}
return true;
}
class set_commit_rollback { class set_commit_rollback {
public: public:
using pointer = void**; using pointer = void**;
...@@ -92,7 +113,7 @@ bool try_match(message_iterator mbegin, message_iterator mend, ...@@ -92,7 +113,7 @@ bool try_match(message_iterator mbegin, message_iterator mend,
return false; // no submatch found return false; // no submatch found
} }
// inspect current element // inspect current element
if (!pbegin->fun(pbegin->type, mbegin, storage.current())) { if (!pbegin->fun(pbegin->v, pbegin->type, mbegin, storage.current())) {
// type mismatch // type mismatch
return false; return false;
} }
......
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