text: #pragma once
  
  #include <ostream>
  #include_next <unordered_map>
  
  #include <elle/print-fwd.hh>
  
  namespace std
  {
    template <typename... Args>
    std::ostream&
    operator <<(ostream& out,
                unordered_map<Args...> const& s)
    {
      auto const format = is_fixed(out) ? "%s%f: %f" : "%s%s: %s";
      out << '{';
      auto* sep = "";
      for (auto const& e: s)
      {
        elle::print(out, format, sep, e.first, e.second);
        sep = ", ";
      }
      out << '}';
      return out;
    }
  
    template <typename... Args>
    class keys_iterator
      : public std::unordered_map<Args...>::iterator
    {
    public:
      using Super = typename std::unordered_map<Args...>::iterator;
      keys_iterator() = default;
      keys_iterator(Super s)
        : Super(s)
      {}
  
      auto
      operator*()
      {
        return Super::operator*().first;
      }
    };
  
    template <typename... Args>
    class const_keys_iterator
      : public std::unordered_map<Args...>::const_iterator
    {
    public:
      using Super = typename std::unordered_map<Args...>::const_iterator;
      const_keys_iterator() = default;
      const_keys_iterator(Super s)
        : Super(s)
      {}
  
      auto
      operator*()
      {
        return Super::operator*().first;
      }
    };
  
    template <typename... Args>
    const_keys_iterator<Args...>
    iter_keys(std::unordered_map<Args...> const& c)
    {
      return const_keys_iterator<Args...>(c.begin());
    }
  
    template <typename... Args>
    const_keys_iterator<Args...>
    iter_keys_end(std::unordered_map<Args...> const& c)
    {
      return const_keys_iterator<Args...>(c.end());
    }
  
    template <typename... Args>
    class values_iterator
      : public std::unordered_map<Args...>::iterator
    {
    public:
      using Super = typename std::unordered_map<Args...>::iterator;
      values_iterator() = default;
      values_iterator(Super s)
        : Super(s)
      {}
  
      auto&
      operator*()
      {
        return Super::operator*().second;
      }
    };
  
    template <typename... Args>
    values_iterator<Args...>
    iter_values(std::unordered_map<Args...>& c)
    {
      return values_iterator<Args...>(c.begin());
    }
  
    template <typename... Args>
    class const_values_iterator
      : public std::unordered_map<Args...>::const_iterator
    {
    public:
      using Super = typename std::unordered_map<Args...>::const_iterator;
      const_values_iterator() = default;
      const_values_iterator(Super s)
        : Super(s)
      {}
  
      auto&
      operator*()
      {
        return Super::operator*().second;
      }
    };
  
    template <typename... Args>
    const_values_iterator<Args...>
    iter_values(std::unordered_map<Args...> const& c)
    {
      return const_values_iterator<Args...>(c.begin());
    }
  
    // http://www.open-std.org/JTC1/SC22/wg21/docs/papers/2014/n4161.htm
    template <typename... Args, typename Pred>
    void erase_if(unordered_map<Args...>& c, Pred pred)
    {
      for (auto it = begin(c); it != end(c);)
        if (pred(*it))
          it = c.erase(it);
        else
          ++it;
    }
  }
  
  // Local Variables:
  // mode: c++
  // End:
  