using Name = nbdl::variant<nbdl::not_found, std::string>;
Name name{};
int result = name.match(
[](nbdl::unresolved) {
return 1;
},
[](std::string const&) {
return 2;
},
[](auto) {
return 3;
});
assert(result == 1);
template <typename DefaultType, typename... Tn>
class variant
{
static_assert(std::is_empty<DefaultType>::value, "DefaultType must be an empty tag struct");
using Storage = typename std::aligned_union<sizeof(DefaultType), DefaultType, Tn...>::type;
using Types = hana::experimental::types<DefaultType, Tn...>;
static auto type_ids()
{
return hana::unpack(hana::range_c<int, 1, sizeof...(Tn)+1>, [](auto ...i) {
return hana::make_map(
hana::make_pair(hana::type_c<DefaultType>, hana::int_c<0>),
hana::make_pair(hana::type_c<Tn>, i)...
);
});
}
using LastTypeId = hana::int_<sizeof...(Tn)>;
int type_id;
Storage value_;
template <typename T>
constexpr int type_id_from_type() const
{
return *hana::find(type_ids(), hana::type_c<T>);
}
...
template <typename Fn1>
auto match_overload(Fn1 fn1) const
{
return fn1;
}
template <typename Fn1, typename Fn2, typename... Fns>
auto match_overload(Fn1 fn1, Fn2 fn2, Fns... fns) const
{
return hana::overload_linearly(fn1, fn2, fns...);
}
...
template <typename... Fns>
auto match(Fns... fns) const
{
auto overload_ = match_overload(fns...);
return match_by_type_helper(hana::int_c<0>, type_id, [&](auto type) {
using T = typename decltype(type)::type;
return overload_(*reinterpret_cast<T const*>(&value_));
});
}
...
template <typename Index, typename Fn>
auto match_by_type_helper(Index i, const int type_id_x, Fn fn) const
-> nbdl::detail::common_type_t<
decltype(fn(hana::at(Types{}, i))),
decltype(fn(hana::at(Types{}, hana::int_c<0>)))
>
{
if (type_id_x == Index::value)
return fn(hana::at(Types{}, i));
else
return match_by_type_helper(i + hana::int_c<1>, type_id_x, fn);
}
template <typename Fn>
auto match_by_type_helper(LastTypeId i, const int type_id_x, Fn fn) const
-> nbdl::detail::common_type_t<
decltype(fn(hana::at(Types{}, i))),
decltype(fn(hana::at(Types{}, hana::int_c<0>)))
>
{
//if type_id_x is invalid, use default, empty type
if (type_id_x == LastTypeId::value)
return fn(hana::at(Types{}, i));
else
return fn(hana::at(Types{}, hana::int_c<0>));
}
constexpr auto nested_accesspoints =
AccessPoints(
AccessPoint(
Name(names::Nested1),
EntityName(names::Nested1),
Actions(Create(), Read(), Update(), Delete())
),
AccessPoint(
Name(names::Nested2),
EntityName(names::Nested2),
AccessPoints(
AccessPoint(
Name(names::Nested3),
EntityName(names::Nested3),
Actions(Create())
)
)
)
);
{
constexpr auto access_point = builder::make_access_point_meta_with_map(
access_point_meta::name = names::Foo,
access_point_meta::actions = mpdef::make_map(nbdl_def::Create()),
access_point_meta::store_container = hana::type_c<void>,
access_point_meta::entity_names = mpdef::make_list(names::Entity1)
);
using PathType = typename decltype(nbdl::path_type<int, entity::e1>)::type;
BOOST_HANA_CONSTANT_ASSERT(
builder::entity_messages(entity_map, access_point)
==
mpdef::make_list(
hana::type_c<hana::tuple<
channel::upstream,
action::create,
PathType,
hana::optional<nbdl::uid>,
hana::optional<entity::e1>
>>,
hana::type_c<hana::tuple<
channel::downstream,
action::create,
PathType,
hana::optional<nbdl::uid>,
hana::optional<bool>,
hana::optional<entity::e1>
>>
)
);
}
struct entity_messages_fn
{
template<typename EntityMap, typename AccessPoint>
constexpr auto operator()(EntityMap entity_map, AccessPoint access_point) const
{
const auto path = builder::path(entity_map, access_point);
const auto entity_type = hana::type_c<typename decltype(path)::type::Entity>;
const auto actions = hana::unpack(access_point_meta::actions(access_point),
mpdef::make_list ^hana::on^ hana::compose(entity_messages_detail::get_action, hana::first));
const auto private_payload = hana::nothing;
const auto messages_meta = hana::unpack(
hana::cartesian_product(mpdef::make_list(
mpdef::make_list(path),
mpdef::make_list(entity_type),
mpdef::make_list(private_payload),
actions,
mpdef::make_list(
nbdl::message::channel::upstream{},
nbdl::message::channel::downstream{}
)
)),
mpdef::make_list ^hana::on^ hana::fuse(builder::make_entity_message_meta)
);
return hana::unpack(messages_meta,
mpdef::make_list ^hana::on^ entity_message_fn<AccessPoint>{}
);
}
};
namespace boost { namespace hana {
template<typename ...T>
struct tag_of<mpdef::list<T...>> { using type = mpdef::list_tag; };
template<>
struct make_impl<mpdef::list_tag>
{ ... };
// Foldable
template<>
struct unpack_impl<mpdef::list_tag>
{ ... };
// Functor
template<>
struct transform_impl<mpdef::list_tag>
{ ... };
// Iterable
template<>
struct at_impl<mpdef::list_tag>
{ ... };
template<>
struct is_empty_impl<mpdef::list_tag>
{ ... };
template<>
struct drop_front_impl<mpdef::list_tag>
{ ... };
// Sequence
template<>
struct Sequence<mpdef::list_tag>
{ static constexpr bool value = true;};
}}//boost::hana
// map paths to providers (many-to-one)
constexpr auto provider_1_paths = hana::make_tuple(
path_1_1,
path_1_2,
path_1_3,
path_1_4
);
constexpr auto provider_2_paths = hana::make_tuple(
path_2_1,
path_2_2,
path_2_3,
path_2_4
);
constexpr auto provider_3_paths = hana::make_tuple(
path_3_1,
path_3_2
);
constexpr auto provider_4_paths = hana::make_tuple(
path_4_1
);
auto result_map = nbdl::make<nbdl::provider_map>(
hana::make_pair(hana::make_type(provider_1_paths), provider_dummy<1>{}),
hana::make_pair(hana::make_type(provider_2_paths), provider_dummy<2>{}),
hana::make_pair(hana::make_type(provider_3_paths), provider_dummy<3>{}),
hana::make_pair(hana::make_type(provider_4_paths), provider_dummy<4>{})
);
result_map[path_1_1].value = 1;
result_map[path_2_1].value = 2;
result_map[path_3_1].value = 3;
result_map[path_4_1].value = 4;
template<typename ...Pair>
struct provider_map
{
// the keys must be `type<set<path...>>`
using Storage = decltype(hana::make_map(std::declval<Pair>()...));
// each key is a hana::set which contain the keys we
// want to use to lookup a provider
using Lookup = decltype(hana::unpack(
hana::flatten(hana::unpack(hana::keys(std::declval<Storage>()),
hana::make_tuple ^hana::on^ detail::extract_keys)),
hana::make_map
));
...
template<typename T>
constexpr decltype(auto) operator[](T t) const&
{
return hana::at_key(storage, hana::at_key(Lookup{}, t));
}
template<typename T>
constexpr decltype(auto) operator[](T t) &
{
return hana::at_key(storage, hana::at_key(Lookup{}, t));
}
template<typename T>
constexpr decltype(auto) operator[](T t) &&
{
return hana::at_key(storage, hana::at_key(Lookup{}, t));
}
Storage storage;
};