Re: Fix move_if_noexcept usages in _Hashtable

2018-12-16 Thread François Dumont
I reviewed this patch following result of making std::pair piecewise 
constructor noexcept:


https://gcc.gnu.org/ml/libstdc++/2018-12/msg00052.html

I restore check of noexcept qualification on move constructor rather 
than alloc::construct cause when dealing with std::pairValue> I want to check for noexcept qualification of Value type move 
constructor and it doesn't really make sens to check for 
alloc::construct when we eventually call allocValue>::construct.


I'll submit this officially once back in stage 1.

François

On 12/4/18 10:43 PM, François Dumont wrote:

On 12/4/18 3:38 PM, Jonathan Wakely wrote:

On 04/12/18 07:45 +0100, François Dumont wrote:

Hi

  This patch fix a minor problem with usage of 
std::move_if_noexcept. We use it to move node content if move 
construtor is noexcept but we eventually use the 
allocator_type::construct method which might be slightly different. 
I think it is better to check for this method noexcept qualification.


This is likely to pessimize some code, since most allocators do not
have an exception-specification on their construct members.

Perhaps but the Standard mandates to call allocator construct so we 
don't have choice. It is surprising to consider value_type move 
constructor when we don't know what allocator construct does.


Most users do not change from std::allocator or, even if they do, do 
not implement construct so impact should be limited.


  Moreover I have added a special overload for nodes containing a 
std::pair. It is supposed to allow move semantic in associative 
containers where Key is stored as const deleting std::pair move 
constructor. In this case we should still move the Value part.


  It doesn't work for the moment because the std::pair piecewise 
constructor has no noexcept qualification. Is there any plan to add 
it ? I think adding it will force including  in stl_pair.h, 
is it fine ?


No feedback on this point ? Is using std::pair piecewise constructor ok ?



  If this evolution is accepted I'll adapt it for _Rb_tree that has 
the same problem.


  Working on this I also notice that content of initialization_list 
is not moved. Is there a plan to make initialization_list iterator 
type like move_iterator ? Should containers use 
__make_move_iterator_if_noexcept ?


No.

Whether to allow moving from std::initializer_list is an active topic,
see
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1249r0.html

Ok, nice, allowing emplace build of values would be even better, I'll 
have a closer look.



  Tested under Linux x86_64 normal mode.

  Ok to commit this first step ?


No, this is not suitable for stage 3. It seems too risky.

We can reconsider it during stage 1, but I'd like to see (at least) a
new test showing a bug with the current code. For example, a type with
a move constructor that is noexcept, but when used with a
scoped_allocator_adaptor (which calls something other than the move
constructor) we incorrectly move elements, and lose data when an
exception happens.



Ok, I'll try.



diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 9a12ad399dc..dfb756cec07 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -266,8 +266,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_Equal, _H1, _H2, _Hash,
 	_RehashPolicy, _Traits>;
 
-  using __reuse_or_alloc_node_type =
-	__detail::_ReuseOrAllocNode<__node_alloc_type>;
+  template
+	using __alloc_node_gen_t =
+	  __detail::_AllocNode<__node_alloc_type, _ConstructF>;
+
+  template
+	using __reuse_or_alloc_node_gen_t =
+	  __detail::_ReuseOrAllocNode<__node_alloc_type, _ConstructF>;
 
   // Metaprogramming for picking apart hash caching.
   template
@@ -400,9 +405,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Assign *this using another _Hashtable instance. Either elements
   // are copy or move depends on the _NodeGenerator.
-  template
+  template
 	void
-	_M_assign_elements(_Ht&&, const _NodeGenerator&);
+	_M_assign_elements(_Ht&&);
 
   template
 	void
@@ -500,7 +505,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   _Hashtable&
   operator=(initializer_list __l)
   {
-	__reuse_or_alloc_node_type __roan(_M_begin(), *this);
+	__reuse_or_alloc_node_gen_t<_Construct_object_a>
+	  __roan(*this, _M_begin());
 	_M_before_begin._M_nxt = nullptr;
 	clear();
 	this->_M_insert_range(__l.begin(), __l.end(), __roan, __unique_keys());
@@ -1047,9 +1053,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  _M_rehash_policy = __ht._M_rehash_policy;
 	  __try
 		{
-		  _M_assign(__ht,
-			[this](const __node_type* __n)
-			{ return this->_M_allocate_node(__n->_M_v()); });
+		  __alloc_node_gen_t<_Construct_object_a> __ang(*this);
+		  _M_assign(__ht, __ang);
 		}
 	  __catch(...)
 		{
@@ -1064,9 +1069,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
   // Reuse allocated buckets and nodes.
-  _M_assign_elements(__ht,
-	[](const 

Re: Fix move_if_noexcept usages in _Hashtable

2018-12-04 Thread François Dumont

On 12/4/18 3:38 PM, Jonathan Wakely wrote:

On 04/12/18 07:45 +0100, François Dumont wrote:

Hi

  This patch fix a minor problem with usage of std::move_if_noexcept. 
We use it to move node content if move construtor is noexcept but we 
eventually use the allocator_type::construct method which might be 
slightly different. I think it is better to check for this method 
noexcept qualification.


This is likely to pessimize some code, since most allocators do not
have an exception-specification on their construct members.

Perhaps but the Standard mandates to call allocator construct so we 
don't have choice. It is surprising to consider value_type move 
constructor when we don't know what allocator construct does.


Most users do not change from std::allocator or, even if they do, do not 
implement construct so impact should be limited.


  Moreover I have added a special overload for nodes containing a 
std::pair. It is supposed to allow move semantic in associative 
containers where Key is stored as const deleting std::pair move 
constructor. In this case we should still move the Value part.


  It doesn't work for the moment because the std::pair piecewise 
constructor has no noexcept qualification. Is there any plan to add 
it ? I think adding it will force including  in stl_pair.h, is 
it fine ?


No feedback on this point ? Is using std::pair piecewise constructor ok ?



  If this evolution is accepted I'll adapt it for _Rb_tree that has 
the same problem.


  Working on this I also notice that content of initialization_list 
is not moved. Is there a plan to make initialization_list iterator 
type like move_iterator ? Should containers use 
__make_move_iterator_if_noexcept ?


No.

Whether to allow moving from std::initializer_list is an active topic,
see
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1249r0.html

Ok, nice, allowing emplace build of values would be even better, I'll 
have a closer look.



  Tested under Linux x86_64 normal mode.

  Ok to commit this first step ?


No, this is not suitable for stage 3. It seems too risky.

We can reconsider it during stage 1, but I'd like to see (at least) a
new test showing a bug with the current code. For example, a type with
a move constructor that is noexcept, but when used with a
scoped_allocator_adaptor (which calls something other than the move
constructor) we incorrectly move elements, and lose data when an
exception happens.



Ok, I'll try.



Re: Fix move_if_noexcept usages in _Hashtable

2018-12-04 Thread Jonathan Wakely

On 04/12/18 07:45 +0100, François Dumont wrote:

Hi

  This patch fix a minor problem with usage of std::move_if_noexcept. 
We use it to move node content if move construtor is noexcept but we 
eventually use the allocator_type::construct method which might be 
slightly different. I think it is better to check for this method 
noexcept qualification.


This is likely to pessimize some code, since most allocators do not
have an exception-specification on their construct members.

  Moreover I have added a special overload for nodes containing a 
std::pair. It is supposed to allow move semantic in associative 
containers where Key is stored as const deleting std::pair move 
constructor. In this case we should still move the Value part.


  It doesn't work for the moment because the std::pair piecewise 
constructor has no noexcept qualification. Is there any plan to add it 
? I think adding it will force including  in stl_pair.h, is it 
fine ?


  If this evolution is accepted I'll adapt it for _Rb_tree that has 
the same problem.


  Working on this I also notice that content of initialization_list is 
not moved. Is there a plan to make initialization_list iterator type 
like move_iterator ? Should containers use 
__make_move_iterator_if_noexcept ?


No.

Whether to allow moving from std::initializer_list is an active topic,
see
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1249r0.html


  Tested under Linux x86_64 normal mode.

  Ok to commit this first step ?


No, this is not suitable for stage 3. It seems too risky.

We can reconsider it during stage 1, but I'd like to see (at least) a
new test showing a bug with the current code. For example, a type with
a move constructor that is noexcept, but when used with a
scoped_allocator_adaptor (which calls something other than the move
constructor) we incorrectly move elements, and lose data when an
exception happens.



Fix move_if_noexcept usages in _Hashtable

2018-12-03 Thread François Dumont

Hi

  This patch fix a minor problem with usage of std::move_if_noexcept. 
We use it to move node content if move construtor is noexcept but we 
eventually use the allocator_type::construct method which might be 
slightly different. I think it is better to check for this method 
noexcept qualification.


  Moreover I have added a special overload for nodes containing a 
std::pair. It is supposed to allow move semantic in associative 
containers where Key is stored as const deleting std::pair move 
constructor. In this case we should still move the Value part.


  It doesn't work for the moment because the std::pair piecewise 
constructor has no noexcept qualification. Is there any plan to add it ? 
I think adding it will force including  in stl_pair.h, is it fine ?


  If this evolution is accepted I'll adapt it for _Rb_tree that has the 
same problem.


  Working on this I also notice that content of initialization_list is 
not moved. Is there a plan to make initialization_list iterator type 
like move_iterator ? Should containers use 
__make_move_iterator_if_noexcept ?


  Tested under Linux x86_64 normal mode.

  Ok to commit this first step ?

    * include/bits/stl_construct.h (__construct_object_a): New.
    (struct _Construct_object_a): New, use latter.
    (__move_construct_object_a): New.
    (struct _Move_construct_object_a): New, use latter.
    (struct _Move_construct_if_noexcept_a): New.
    * include/std/tuple (__move_construct_object_a): New overload for
    std::pair.
    * include/ext/throw_allocator.h
    (throw_allocator_base<>::construct<_Up, _Args...>): Add noexcept
    qualification.
    * testsuite/util/testsuite_allocator.h
    (tracker_allocator<>::construct<_Up, _Args...>): Likewise.
    * include/bits/hashtable_policy.h: Include 
    (_Hashtable_alloc<>::_M_allocate_node_f): New.
    (_Hashtable_alloc<>::_M_allocate_node): Adapt, use latter.
    (_AllocNode<>::operator()<_Args...>): Likewise.
    (_AllocNode<_NodeAlloc, _ConstructF>): Inherit from _ConstructF.
    (_AllocNode<>::_M_construct_f()): New.
    (_ReuseOrAllocNode<>): Inherits from _AllocNode.
    * include/bits/hashtable.h:
    (_Hashtable<>::__alloc_node_gen_t): New template alias to _NodeAlloc.
    (_Hashtable<>::__reuse_or_alloc_node_type): Replace with...
    (_Hashtable<>::__reuse_or_alloc_node_gen_t): ...that.
    (_Hashtable<>::_M_assign_elements<>): Remove _NodeGenerator parameter.
    (_Hashtable<>::operator=(initializer_list<>)): Adapt.
    (_Hashtable<>::operator=(const _Hashtable&)): Adapt.
    (_Hashtable<>::_M_move_assign(_Hashtable&&, false_type)): Adapt.
    (_Hashtable<>::_Hashtable(const _Hashtable&)): Adapt.
    (_Hashtable<>::_Hashtable(const _Hashtable&, const allocator_type&)):
    Adapt.
    (_Hashtable<>::_Hashtable(_Hashtable&&, const allocator_type&)): Adapt.
    * testsuite/23_containers/unordered_map/allocator/move_assign.cc:
    (test01): Add checks.
    (test02): Likewise.
    * testsuite/23_containers/unordered_set/allocator/move_assign.cc:
    (test04): New.

François

diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 9a12ad399dc..dfb756cec07 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -266,8 +266,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_Equal, _H1, _H2, _Hash,
 	_RehashPolicy, _Traits>;
 
-  using __reuse_or_alloc_node_type =
-	__detail::_ReuseOrAllocNode<__node_alloc_type>;
+  template
+	using __alloc_node_gen_t =
+	  __detail::_AllocNode<__node_alloc_type, _ConstructF>;
+
+  template
+	using __reuse_or_alloc_node_gen_t =
+	  __detail::_ReuseOrAllocNode<__node_alloc_type, _ConstructF>;
 
   // Metaprogramming for picking apart hash caching.
   template
@@ -400,9 +405,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Assign *this using another _Hashtable instance. Either elements
   // are copy or move depends on the _NodeGenerator.
-  template
+  template
 	void
-	_M_assign_elements(_Ht&&, const _NodeGenerator&);
+	_M_assign_elements(_Ht&&);
 
   template
 	void
@@ -500,7 +505,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   _Hashtable&
   operator=(initializer_list __l)
   {
-	__reuse_or_alloc_node_type __roan(_M_begin(), *this);
+	__reuse_or_alloc_node_gen_t<_Construct_object_a>
+	  __roan(*this, _M_begin());
 	_M_before_begin._M_nxt = nullptr;
 	clear();
 	this->_M_insert_range(__l.begin(), __l.end(), __roan, __unique_keys());
@@ -1047,9 +1053,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  _M_rehash_policy = __ht._M_rehash_policy;
 	  __try
 		{
-		  _M_assign(__ht,
-			[this](const __node_type* __n)
-			{ return this->_M_allocate_node(__n->_M_v()); });
+		  __alloc_node_gen_t<_Construct_object_a> __ang(*this);
+		  _M_assign(__ht, __ang);
 		}
 	  __catch(...)
 		{
@@ -1064,9 +1069,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
   // Reuse allocated buckets and nodes.
-  _M_assign_elements(__ht,
-