Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 578
Vittorio Romeo Avatar asked May 23 '16 08:05

Vittorio Romeo


2 Answers

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.

like image 149
Jason Rice Avatar answered Nov 15 '22 02:11

Jason Rice


Do you need to change the type of the value? If not, and if your value can be assigned to, you can use map[key] = new_value or equivalently hana::at_key(map, key) = new_value, as hana::at_key returns a reference.

If you need the type of the value to change, that's more tricky. We won't be able to do anything in-place, because the type of the map after replacing the value will be different from its type before replacing the value. Hence, we have to create a new map or some kind of modified view of that map (but views are not currently supported). Using erase_key and insert will indeed cause two maps to be created, which is inefficient. Instead, we could provide some kind of update function that would achieve the same, but would create only one copy of the map (the result). I believe we could also do better than erase_key + insert in terms of compilation times by providing our own function. I opened this issue to keep track of your request, since I think it is important to provide something like this; thanks.

Finally, I'd like to comment what Jason said:

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

hana::map could be made a Functor, but I'm not sure that transform could touch the keys of the map while still respecting the Functor laws. If that's not the case, you still wouldn't be able to say "replace the value with XXX if the key satisfies some predicate" using e.g. hana::replace_if. I tried (but failed so far) to find an example of functions that would break the laws if hana::transform basically transformed the sequence of underlying key/value pairs, but my intuition is that it's possible to find such an example. To be continued in issue #278.

like image 36
Louis Dionne Avatar answered Nov 15 '22 03:11

Louis Dionne