Skip to content

Commit

Permalink
Implement new syntax for atom constants
Browse files Browse the repository at this point in the history
  • Loading branch information
Neverlord committed Jan 20, 2015
1 parent 7b9905d commit 18bcf49
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 48 deletions.
24 changes: 20 additions & 4 deletions libcaf_core/caf/atom.hpp
Expand Up @@ -47,11 +47,27 @@ constexpr atom_value atom(char const (&str)[Size]) {
}

/**
* Type alias for treating atom constants at compile-time
* (cf. "Int-ToType" idiom).
* Lifts an `atom_value` to a compile-time constant.
*/
template <atom_value Value>
using atom_constant = std::integral_constant<atom_value, Value>;
template <atom_value V>
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.
Expand Down
33 changes: 31 additions & 2 deletions libcaf_core/caf/detail/ctm.hpp
Expand Up @@ -35,8 +35,25 @@ namespace detail {
template <class A, class B>
struct ctm_cmp : std::false_type { };

template <class T>
struct ctm_cmp<T, T> : std::true_type { };
template <class In, class L, class R1, class R2>
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>
struct ctm_cmp<typed_mpi<In, Out, empty_type_list>,
Expand All @@ -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>>
: 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>
struct ctm : std::false_type { };

Expand Down
9 changes: 7 additions & 2 deletions libcaf_core/caf/detail/lifted_fun.hpp
Expand Up @@ -148,10 +148,15 @@ class lifted_fun_invoker<bool, F> {
*/
template <class F, class ListOfProjections, class... Args>
class lifted_fun {

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>
// unless R is void in which case bool is returned
Expand Down
44 changes: 13 additions & 31 deletions libcaf_core/caf/detail/try_match.hpp
Expand Up @@ -24,6 +24,7 @@
#include <numeric>
#include <typeinfo>

#include "caf/atom.hpp"
#include "caf/message.hpp"
#include "caf/wildcard_position.hpp"

Expand All @@ -33,56 +34,37 @@
namespace caf {
namespace detail {

bool match_element(const std::type_info* type, const message_iterator& iter,
void** storage);
bool match_element(const atom_value&, const std::type_info* type,
const message_iterator& iter, void** storage);

template <class T>
bool match_integral_constant_element(const std::type_info* type,
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;
}
bool match_atom_constant(const atom_value&, const std::type_info* type,
const message_iterator& iter, void** storage);

struct meta_element {
atom_value v;
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>
struct meta_element_factory {
static meta_element create() {
return {&typeid(T), match_element};
return {static_cast<atom_value>(0), &typeid(T), match_element};
}
};

template <class T, T V>
struct meta_element_factory<std::integral_constant<T, V>> {
template <atom_value V>
struct meta_element_factory<atom_constant<V>> {
static meta_element create() {
return {&typeid(T),
match_integral_constant_element<std::integral_constant<T, V>>};
return {V, &typeid(atom_value), match_atom_constant};
}
};

template <>
struct meta_element_factory<anything> {
static meta_element create() {
return {nullptr, nullptr};
return {static_cast<atom_value>(0), nullptr, nullptr};
}
};

Expand Down
13 changes: 7 additions & 6 deletions libcaf_core/caf/message.hpp
Expand Up @@ -22,6 +22,7 @@

#include <type_traits>

#include "caf/atom.hpp"
#include "caf/config.hpp"

#include "caf/detail/int_list.hpp"
Expand Down Expand Up @@ -282,13 +283,13 @@ inline bool operator!=(const message& lhs, const message& rhs) {
}

template <class T>
struct lift_message_element {
struct unbox_message_element {
using type = T;
};

template <class T, T V>
struct lift_message_element<std::integral_constant<T, V>> {
using type = T;
template <atom_value V>
struct unbox_message_element<atom_constant<V>> {
using type = atom_value;
};

/**
Expand All @@ -303,10 +304,10 @@ typename std::enable_if<
>::type
make_message(T&& arg, Ts&&... args) {
using storage
= detail::tuple_vals<typename lift_message_element<
= detail::tuple_vals<typename unbox_message_element<
typename detail::strip_and_convert<T>::type
>::type,
typename lift_message_element<
typename unbox_message_element<
typename detail::strip_and_convert<Ts>::type
>::type...>;
auto ptr = new storage(std::forward<T>(arg), std::forward<Ts>(args)...);
Expand Down
27 changes: 24 additions & 3 deletions libcaf_core/src/try_match.cpp
Expand Up @@ -28,8 +28,8 @@ bool is_wildcard(const meta_element& me) {
return me.type == nullptr;
}

bool match_element(const std::type_info* type, const message_iterator& iter,
void** storage) {
bool match_element(const atom_value&, const std::type_info* type,
const message_iterator& iter, void** storage) {
if (!iter.type()->equal_to(*type)) {
return false;
}
Expand All @@ -39,6 +39,27 @@ bool match_element(const std::type_info* type, const message_iterator& iter,
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 {
public:
using pointer = void**;
Expand Down Expand Up @@ -92,7 +113,7 @@ bool try_match(message_iterator mbegin, message_iterator mend,
return false; // no submatch found
}
// inspect current element
if (!pbegin->fun(pbegin->type, mbegin, storage.current())) {
if (!pbegin->fun(pbegin->v, pbegin->type, mbegin, storage.current())) {
// type mismatch
return false;
}
Expand Down

0 comments on commit 18bcf49

Please sign in to comment.