Using Boost.Hana

A Couple of Use Cases

A Lightweight Variant

  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>));
      }

Generate Message Types

    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

Mapping to Maps

    // 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;
};

using_boost_hana

By Jason Rice

using_boost_hana

  • 491