On Sat, Aug 4, 2012 at 10:34 AM, Paolo Carlini <paolo.carl...@oracle.com> wrote:
>
>
> First, I think we should add libstdc++ in CC.
>
> Thus, I would recommend people working in this area to begin with
> unordered_map, because in that case emplace is already available, assuming
> that's really the point (and therefore reverting the patch was a good idea,
> luckily an existing testcase helped us)
>
> At the same time an implementation of emplace is definitely welcome, in
> any case.

I've attached a patch for unordered_map which solves the rvalue
reference problem.  For efficiency, I've created a new
_M_emplace_bucket method rather than call emplace directly.

I've verified all libstdc++ tests pass (sorry for the previous
oversight) and am running the full GCC test suite now.  However, I'd
appreciate any feedback on whether this is a reasonable approach.  STL
hacking is way outside my comfort zone.  ;-)

If this looks good, I'll take a stab at std::map.

Thanks,
Ollie


2012-08-03  Ollie Wild  <a...@google.com>

        * include/bits/hashtable.h (_M_emplace_bucket): New function.
        * include/bits/hashtable_policy.h (operator[](key_type&&)): Replace
        _M_insert_bucket call with _M_emplace_bucket.
        * testsuite/23_containers/unordered_map/operators/2.cc: New test.
commit dd690a5f164326c552c2450af6270ec27e9bfd8e
Author: Ollie Wild <a...@google.com>
Date:   Tue Aug 7 16:34:05 2012 -0500

    2012-08-03  Ollie Wild  <a...@google.com>
    
        * include/bits/hashtable.h (_M_emplace_bucket): New function.
        * include/bits/hashtable_policy.h (operator[](key_type&&)): Replace
        _M_insert_bucket call with _M_emplace_bucket.
        * testsuite/23_containers/unordered_map/operators/2.cc: New test.

 2012-08-04  Paolo Carlini  <paolo.carl...@oracle.com>
 
        Revert:
diff --git a/libstdc++-v3/include/bits/hashtable.h 
b/libstdc++-v3/include/bits/hashtable.h
index 2faf0b3..869b0e9 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -588,6 +588,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        iterator
        _M_insert_bucket(_Arg&&, size_type, __hash_code);
 
+      template<typename... _Args>
+       iterator
+       _M_emplace_bucket(size_type, __hash_code, _Args&&... __args);
+
 
       template<typename... _Args>
        std::pair<iterator, bool>
@@ -1356,6 +1360,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          }
       }
 
+  // Insert v in bucket n (assumes no element with its key already present).
+  template<typename _Key, typename _Value,
+          typename _Alloc, typename _ExtractKey, typename _Equal,
+          typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
+          typename _Traits>
+    template<typename... _Args>
+      typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+                         _H1, _H2, _Hash, _RehashPolicy,
+                         _Traits>::iterator
+      _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
+      _M_emplace_bucket(size_type __n, __hash_code __code, _Args&&... __args)
+      {
+       // First build the node to get access to the hash code
+       __node_type* __node = _M_allocate_node(std::forward<_Args>(__args)...);
+       __try
+         {
+
+           const __rehash_state& __saved_state = _M_rehash_policy._M_state();
+           std::pair<bool, std::size_t> __do_rehash
+             = _M_rehash_policy._M_need_rehash(_M_bucket_count,
+                                               _M_element_count, 1);
+
+           if (__do_rehash.first)
+             {
+               const key_type& __k = this->_M_extract()(__node->_M_v);
+               __n = __hash_code_base::_M_bucket_index(__k, __code,
+                                                       __do_rehash.second);
+             }
+
+           this->_M_store_code(__node, __code);
+           if (__do_rehash.first)
+             _M_rehash(__do_rehash.second, __saved_state);
+
+           _M_insert_bucket_begin(__n, __node);
+           ++_M_element_count;
+           return iterator(__node);
+         }
+       __catch(...)
+         {
+           _M_deallocate_node(__node);
+           __throw_exception_again;
+         }
+      }
+
   // Insert v if no element with its key is already present.
   template<typename _Key, typename _Value,
           typename _Alloc, typename _ExtractKey, typename _Equal,
diff --git a/libstdc++-v3/include/bits/hashtable_policy.h 
b/libstdc++-v3/include/bits/hashtable_policy.h
index 27790f2..addf9d13 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -598,9 +598,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __node_type* __p = __h->_M_find_node(__n, __k, __code);
 
       if (!__p)
-       return __h->_M_insert_bucket(std::make_pair(std::move(__k),
-                                                   mapped_type()),
-                                    __n, __code)->second;
+       return __h->_M_emplace_bucket(__n, __code,
+                                     std::move(__k), mapped_type())->second;
       return (__p->_M_v).second;
     }
 
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/operators/2.cc 
b/libstdc++-v3/testsuite/23_containers/unordered_map/operators/2.cc
new file mode 100644
index 0000000..1940fa2
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/operators/2.cc
@@ -0,0 +1,44 @@
+// Copyright (C) 2012
+// Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// 23.5.4 template class unordered_map
+
+// This test verifies that the value type of a unordered_map need not be
+// default copyable.
+
+// { dg-do compile }
+// { dg-options "-std=gnu++11" }
+
+#include <unordered_map>
+#include <testsuite_rvalref.h>
+
+struct Mapped {
+    Mapped() = default;
+    explicit Mapped(const Mapped&) = default;
+};
+
+void foo()
+{
+  using __gnu_test::rvalstruct;
+
+  std::unordered_map<int, Mapped> m1;
+  m1[0] = Mapped();
+
+  std::unordered_map<int, rvalstruct> m2;
+  m2[0] = rvalstruct(13);
+}

Reply via email to