Search code examples
c++boostmetaprogrammingc++14boost-hana

Canonical way of updating/replacing a map value in `boost::hana::map`


What is the canonical way of updating a value (given a key and a new value) inside a boost::hana::map?

I tried using boost::hana::replace_if but it does not work on map as it is not a Functor - I can get it to work by converting the map to a tuple and then back to a map, but it sounds inefficient.

The alternative I'm currently using is calling map::erase_key followed by map::insert.

Is there any replace or update function designed for this purpose that I might be missing? Or is this the "canonical" way of updating a value?


Solution

  • I don't think there is currently a canonical way to do this. If there are valid use cases for this, perhaps we could get a function in there to support it. The problem with hana::erase_key is that you will be creating a new map and then again with hana::insert. For the time being, using hana::unpack and then creating a new map is probably your best bet.

    #include <boost/hana.hpp>
    
    namespace hana = boost::hana;
    
    template <typename NewPair>
    struct replace_helper_t
    {
      NewPair const& new_pair;
    
      template <typename Pair>
      constexpr decltype(auto) operator()(Pair&& p) const
      {
        return hana::if_(
          hana::equal(hana::first(new_pair), hana::first(p)),
          new_pair,
          std::forward<Pair>(p)
        );
      }
    };
    
    struct replace_t
    {
      template <typename Map, typename NewPair>
      constexpr auto operator()(Map&& m, NewPair&& new_pair) const
      {
        return hana::unpack(std::forward<Map>(m),
          hana::on(
            hana::make_map,
            replace_helper_t<NewPair>{std::forward<NewPair>(new_pair)}
          )
        );
      }
    };
    
    constexpr replace_t replace{};
    
    int main()
    {
      auto my_map = hana::make_map(
        hana::make_pair(hana::int_c<7>, 7),
        hana::make_pair(hana::int_c<13>, 13),
        hana::make_pair(hana::int_c<23>, 23)
      );
    
      auto new_map = replace(my_map, hana::make_pair(hana::int_c<13>, 14.0f));
    
      BOOST_HANA_RUNTIME_ASSERT(new_map ==
        hana::make_map(
          hana::make_pair(hana::int_c<7>, 7),
          hana::make_pair(hana::int_c<13>, 14.0f),
          hana::make_pair(hana::int_c<23>, 23)
        )
      );
    }
    

    On another note, perhaps hana::map should be a Functor.