<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
  <head>
    <meta content="text/html;charset=UTF-8" http-equiv="Content-Type">
    <title>Improved insertion interface for std::{unordered_,}map (revised)</title>
    <style type="text/css">
      html { margin: 0; padding: 0; color: black; background-color: white; }
      body { padding: 2em; font-size: medium; font-family: "DejaVu Serif", serif; line-height: 150%; }
      code { font-family: "DejaVu Sans Mono", monospace; color: #006; }

      h1, h2, h3 { margin: 1.5em 0 .75em 0; line-height: 125%; }

      div.code { white-space: pre-line; font-family: "DejaVu Sans Mono", monospace;
                 border: thin solid #E0E0E0; background-color: #F8F8F8; padding: 1em;
                 border-radius: 4px; }

      div.strictpre { white-space: pre; }

      .docinfo { float: right }
      .docinfo p { margin: 0; text-align:right; }
      .docinfo address { font-style: normal; }

      .quote { display: inline-block; clear: both; margin-left: 1ex;
                 border: thin solid #E0E0E0; background-color: #F8F8F8; padding: 1ex; }

      .insert { border-left: thick solid #0A0; border-right: thick solid #0A0; padding: 0 1em; }
      .comment { color: #456; }
      .inclassit { font-family: "DejaVu Serif", serif; font-style: italic; }
      .insinline { border-bottom: 2px solid #0A0; }
    </style>
  </head>
  <body>
    <div class="docinfo">
      <p>ISO/IEC JTC1 SC22 WG21 N4279</p>
      <p>Date: 2014-11-07</p>
      <address>Thomas K&ouml;ppe &lt;<a href="mailto:tkoeppe@google.com">tkoeppe@google.com</a>&gt;</address>
    </div>

    <h1>Improved insertion interface for unique-key maps (Revision 2.3)</h1>

    <h2>Revision history</h2>
    <ul>
      <li>20 Jan 2014: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3873.html">N3873</a>, initial proposal</li>
      <li>26 May 2014: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4006.html">N4006</a>, consideration of alternatives (dropped, decision to pursue N3873)</li>
      <li>11 Oct 2014: N4240, this version (revises N3873)</li>
      <li>02 Nov 2014: fixes signature of hinted overloads, adds rvalue overloads (rev 2.1)</li>
      <li>06 Nov 2014: applied LWG changes to proposed wording (rev 2.2)</li>
      <li>07 Nov 2014: N4279, added missing synopses (rev 2.3)</li>
    </ul>

    <h2>Contents</h2>
    <!-- fgrep -e "<h2 id=" map-proposal-v2.3.html | sed -e 's/.*id="\(.*\)">\(.*\)<\/h2>/<li><a href="#\1">\2<\/a><\/li>/g' -->
    <ol>
      <li><a href="#background">Background</a></li>
      <li><a href="#summary">Summary</a></li>
      <li><a href="#impact">Impact on the standard</a></li>
      <li><a href="#spec">Technical specifications</a></li>
      <li><a href="#notes">Notes</a></li>
      <li><a href="#questions">Questions for the WG</a></li>
    </ol>

    <h2 id="background">Background</h2>

    <p>The existing interface of unique-keyed map containers (<code>std::map</code>,
      <code>std::unordered_map</code>) is slightly underspecified, which makes certain
      container mutations more complicated to write and error-prone than necessary. This paper describes
      new member function templates to fill this gap.</p>
    
    <p>The justification and rationale for the new interface are given in
      <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3873.html">N3873</a>.
      The initial reaction to N3873 in Issaquah was that the existing map interfaces should
      be fixed rather than adding new interfaces. We explored this idea in 
      <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4006.html">N4006</a>
      in Rapperswil
      and decided that the original proposal was preferable (with some name changes). This
      paper only summarises the proposed extension without repeating the original discussion.
      We only restate the motivating code snippet here for motivation:</p>

    <div class="code">std::map&lt;std::string, std::unique_ptr&lt;Foo&gt;&gt; m;
      m["foo"] = nullptr;

      auto ptr = std::make_unique_ptr&lt;Foo&gt;;
      auto res = m.emplace("foo", std::move(ptr));

      assert(ptr);&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// ??? (may or may not fire)</span>
    </div>

    <h2 id="summary">Summary</h2>

    <p>To each of the unique-keyed map container templates <code>std::map</code> and
    <code>std::unordered_map</code>, we propose to add the following new, specialised
    algorithms:</p>

    <ul>
      <li><code>try_emplace()</code>: if the key already exists, does not
      insert anything and does not modify the arguments.</li>
      <li><code>insert_or_assign()</code>: inserts the mapped element or
        assigns it to the current element if the key already exists.</li>
    </ul>

    <p>The utility of these two algorithms lies in the fact that they make mutations possible
      that would be verbose to spell out, error-prone, surprising and hard to teach with the
      existing interface. Moreover, the algorithms can perform their actions as efficiently as
      possible, since they are able to take advantage of the internal structure of the
      container, thus filling a gap where users might previously have felt that they &ldquo;could do
      it better by hand&rdquo;. Briefly:</p>

    <ul>
      <li><code>try_emplace</code> does not steal from the arguments if the insertion does not
        happen, unlike <code>insert</code>
        or <code>emplace</code>. Using <code>insert</code> or <code>emplace</code>, the user would
        have to perform a separate <code>find</code> call to prevent stealing from the argument.
        As the motivating code snippet demonstrates, it might not even show as an error if the user
        forgot to do this and wrote erroneous code.</li>
      <li><code>insert_or_assign</code> returns more information than <code>operator[]</code> and does
        not require
        default-constructibility of the mapped type. To achieve the same result with the current interface,
        one would need <code>find</code>, followed by a separate insertion if the
        key did not already exist.</li>
    </ul>

    <p>Finally, since both new algorithms separate parameters into key and mapped type components,
      they are somewhat more intuitive than the generic container mutators that are expressed in
      terms of <code>value_type</code> (which is a <code>std::pair</code>). This point is often
      confusing or annoying to users and hard to teach.</p>

    <h2 id="impact">Impact on the standard</h2>
    <p>This is purely an extension of the standard library. Eight new function templates have to be added to
    [map.modifiers] and to [unord.maps.modifiers]. There is no interference with existing code.</p>

    <h2 id="spec">Technical specifications</h2>

    <p>Add the following to [maps.modifiers] and to [unord.maps.modifiers]:</p>

    <div class="insert">
      <div class="code">template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(const key_type&amp; k, Args&amp;&amp;... args);
        template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(key_type&amp;&amp; k, Args&amp;&amp;... args);
        template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, const key_type&amp; k, Args&amp;&amp;... args);
        template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, key_type&amp;&amp; k, Args&amp;&amp;... args);</div>

      <p><em>Effects:</em> If the key <code>k</code> already exists in the map, there is no effect.
        Otherwise, inserts an element into the map. In the first and third forms, the element is
        constructed from the arguments as <code>value_type(k, std::forward&lt;Args&gt;(args)...)</code>.
        In the second and fourth forms, the element is constructed from the arguments as
        <code>value_type(std::move(k), std::forward&lt;Args&gt;(args)...)</code>.
        In the first two overloads, the <code>bool</code> component of the returned pair is true if and only if the insertion
        took place.
        The returned <code>iterator</code> points to the element of the map whose key
        is equivalent to <code>k</code>.</p>

      <p><em>Complexity:</em> The same as <code>emplace</code> and <code>emplace_hint</code>,
      respectively.</p>

      <div class="code">template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(const key_type&amp; k, M&amp;&amp; obj);
        template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(key_type&amp;&amp; k, M&amp;&amp; obj);
        template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, const key_type&amp; k, M&amp;&amp; obj);
        template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, key_type&amp;&amp; k, M&amp;&amp; obj);</div>

      <p><em>Effects:</em> If the key <code>k</code> does not exist in the map,
        inserts an element into the map.
        In the first and third forms, the element is
        constructed from the arguments as <code>value_type(k, std::forward&lt;Args&gt;(args)...)</code>.
        In the second and fourth forms, the element is constructed from the arguments as
        <code>value_type(std::move(k), std::forward&lt;Args&gt;(args)...)</code>.
        If the key already exists, <code>std::forward&lt;M&gt;(obj)</code> is assigned to the <code>mapped_type</code> corresponding to the key.
        In the first two overloads, the <code>bool</code> component of the returned value is true if and only if the insertion took place.
        The returned <code>iterator</code> points to the element that was inserted or updated.</p>

      <p><em>Complexity:</em> The same as <code>emplace</code> and <code>emplace_hint</code>,
      respectively.</p>
    </div>

    <p>Also add the function declarations to the synopses. In [map.overview]/2, add:</p>
    <div class="insert">
      <div class="code"><span class="inclassit">// 23.4.4.4, modifiers</span>
[...]
<span class="insinline">template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(const key_type&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(key_type&amp;&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, const key_type&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, key_type&amp;&amp; k, Args&amp;&amp;... args);
template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(const key_type&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(key_type&amp;&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, const key_type&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, key_type&amp;&amp; k, M&amp;&amp; obj);</span></div>
    </div>

    <p>Similarly, add to [unord.map.overview]/3:</p>

    <div class="insert">
      <div class="code"><span class="inclassit">// modifiers</span>
[...]
<span class="insinline">template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(const key_type&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(key_type&amp;&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, const key_type&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, key_type&amp;&amp; k, Args&amp;&amp;... args);
template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(const key_type&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(key_type&amp;&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, const key_type&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, key_type&amp;&amp; k, M&amp;&amp; obj);</span></div>
    </div>

    <h2 id="notes">Notes</h2>

    <p>The original names in N3873 were &ldquo;<code>emplace_stable</code>&rdquo; and
      &ldquo;<code>emplace_or_update</code>&rdquo;, and both took only a single second
      parameter <code>M && obj</code>. In Rapperswil, the names <code>try_emplace</code>
      and <code>emplace_or_assign</code> were proposed, and the question arose whether
      the signatures could be variadic.</p>
    <p>Making <code>try_emplace</code> variadic seems to pose no further obstacle, and
      this is how it appears in this paper. As for <code>emplace_or_assign</code>, we
      agreed that a variadic signature would not fit well with assignment (we never
      have variadic assignment operations in the standard), so we retained the single-parameter
      form here. However, with a single argument the function feels less like an &ldquo;emplace&rdquo;
      and more like an &ldquo;insert&rdquo;, which is why we are tentatively proposing the
      name <code>insert_or_update</code> here. Naturally, this is up to debate.</p>
    <p>In Rapperswil and subsequent discussions it was also suggested to include overloads
      in which the key parameter is taken by mutable rvalue reference. These overloads were
      added in revision v2.1, which was presented to LEWG, for the reason that without them, the new interface would be
      worse than the existing <code>insert</code>/<code>emplace</code> interface in certain cases.</p>
    <p>We are not considering templated key parameters and support for
      transparent comparators; transparent comparators are currently only considered for
      look-up functions, not for mutators.</p>

    <h2 id="questions">Questions for the WG</h2>

    <p>Questions in poll form.</p>

    <ul>
      <li>I prefer the variadic signature
        <code>try_emplace(const key_type &amp, Args &amp;&amp;...)</code> rather than
        the originally proposed <code>try_emplace(const key_type &amp, M &amp;&amp;)</code>.
      </li>
      <li>The name change from <code>emplace_or_assign</code> to <code>insert_or_assign</code> is appropriate.</li>
      <li>We can deal with generalising the key parameter for transparent comparators separately, not now.</li>
    </ul>

  </body>
</html>
