[PATCH] Fix pretty printers tests

2019-12-13 Thread François Dumont
Here is a patch to fix prettyprinters.exp failures in normal and debug 
modes.


In 80276.cc I replicate the #define with comment from other tests even 
if it isn't true that cxx11 abi string isn't supported. It's just that 
it doesn't appear as 'std::string', the aliasing doesn't work.


I still have failures when running with versioned namespace which I am 
going to check now.


    * python/libstdcxx/v6/printers.py (lookup_node_type): Remove redundant
    call to lookup_node_type.
    * testsuite/libstdc++-prettyprinters/80276.cc: Define
    _GLIBCXX_USE_CXX11_ABI to 0.
    * testsuite/libstdc++-prettyprinters/91997.cc: Use regexp-test to check
    'a' content.

Ok to commit ?

François

diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 08327516b28..5119e6fab7e 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -146,7 +146,6 @@ def lookup_node_type(nodename, containertype):
 if is_member_of_namespace(containertype, 'std::__cxx1998',
   'std::__debug', '__gnu_debug'):
 nodename = nodename.replace('::', '::__cxx1998::', 1)
-return lookup_templ_spec(nodename, valtype)
 try:
 return lookup_templ_spec(nodename, valtype)
 except gdb.error:
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/80276.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/80276.cc
index 3425b499e3a..272adb86e0c 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/80276.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/80276.cc
@@ -18,6 +18,9 @@
 // with this library; see the file COPYING3.  If not see
 // .
 
+// Type printers only recognize the old std::string for now.
+#define _GLIBCXX_USE_CXX11_ABI 0
+
 #include 
 #include 
 #include 
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/91997.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/91997.cc
index 393c5680e2e..059ac9aa97f 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/91997.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/91997.cc
@@ -41,7 +41,7 @@ int main()
   // { dg-final { note-test mit {{first = 1, second = 2}} } }
 
   std::any a = m;
-  // { dg-final { note-test a {std::any containing std::map with 1 element = {[1] = 2}} } }
+  // { dg-final { regexp-test a {std::any containing std::(__debug::)?map with 1 element = {\[1\] = 2}} } }
 
   std::set s{1, 2};
   auto sit = s.begin();


[PATCH] Fix gnu-versioned-namespace tr1 declaration

2019-12-11 Thread François Dumont

On 12/11/19 12:22 PM, Jonathan Wakely wrote:

On 11/12/19 11:16 +, Jonathan Wakely wrote:

On 11/12/19 08:29 +0100, François Dumont wrote:

I plan to commit this tomorrow.

Note that rather than just adding the missing 
_GLIBCXX_[BEGIN,END]_VERSION_NAMESPACE I also move anonymous 
namespace usage outside std namespace. Let me know if it was 
intentional.


It was intentional, why move it?

Adding the BEGIN/END_VERSION macros is unnecessary. Those namespaces
are inline, so std::random_device already refers to
std::__8::random_device when the original declaration was in the
versioned namespace.

The only fix needed here seems to be qualifying std::isdigit (and
strictly-speaking we should also include  to declare that).


I was curious why that qualification is needed. Th problem is that
 is being indirectly included by some other header, and so is
, so the declarations visible are ::isdigit(int) and
std::__8::isdigit(CharT, const locale&). Even after including
 we still can't call it unqualified, because  doesn't
use the versioned namespace:


Yes, this is the other patch I wanted to propose. Make sure that tr1 
namespace is always defined consistently with the version namespace.


For instance 17_intro/headers/c++2011/parallel_mode.cc is failing at the 
moment with:


/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/tr1/gamma.tcc:292: 
error: reference to 'tr1' is ambiguous
In file included from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/tr1/random:45,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/parallel/random_number.h:36,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/parallel/partition.h:38,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/parallel/quicksort.h:36,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/parallel/sort.h:48,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/parallel/algo.h:45,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/parallel/algorithm:37,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/algorithm:80,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/stdc++.h:65,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/extc++.h:32,
 from 
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/17_intro/headers/c++2011/parallel_mode.cc:24:
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/tr1/type_traits:40: 
note: candidates are: 'namespace std::__8::tr1 { }'
In file included from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/parallel/types.h:37,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/parallel/parallel.h:38,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/parallel/base.h:40,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/parallel/algobase.h:40,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_algobase.h:2071,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/char_traits.h:39,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/ios:40,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/istream:38,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/sstream:38,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/complex:45,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/ccomplex:39,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/stdc++.h:54,
 from 
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/extc++.h:32,
 from 
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/17_intro/headers/c++2011/parallel_mode.cc:24:
/home/fdt/dev/gcc/build_versioned_ns/x86_64-pc-linux-gnu/libstdc++-v3/include/tr1/cstdint:61: 
note: 'namespace std::tr1 { }'


Tested under Linux x86_64 normal and versioned namespace.

Ok to commit ?

François


diff --git a/libstdc++-v3/include/tr1/cctype b/libstdc++-v3/include/tr1/cctype
index ce994066188..b35cd04f0db 10

Re: [PATCH] Fix gnu-versioned-namespace build

2019-12-11 Thread François Dumont

On 12/11/19 9:44 PM, Jonathan Wakely wrote:

On 11/12/19 21:23 +0100, François Dumont wrote:

On 12/11/19 12:16 PM, Jonathan Wakely wrote:

On 11/12/19 08:29 +0100, François Dumont wrote:

I plan to commit this tomorrow.

Note that rather than just adding the missing 
_GLIBCXX_[BEGIN,END]_VERSION_NAMESPACE I also move anonymous 
namespace usage outside std namespace. Let me know if it was 
intentional.


It was intentional, why move it?


I just don't get the intention so I proposed to move it. But there 
are indeed other usages of this pattern in other src files.


Note that in src/c++11/debug.cc I am using anonymous namespace at 
global scope, is that wrong ?


It's certainly more fragile, so arguably it's wrong, yes.

Consider:

// some libc function in a system header we don't control:
extern "C" void __foo();

// libstdc++ code in a .cc file:
namespace
{
 void foo() { }
}
namespace std
{
 void bar() { foo(); }
}

This fails to compile, because the name foo is ambiguous in the global
scope. We don't control the libc headers, so we don't know all the
names they might declare at global scope.

If you don't put the unnamed namespace at global scope, the problem
simply doesn't exist:

namespace std
{
 namespace
 {
   void foo() { }
 }

 void bar() { foo(); }
}

Now it doesn't matter what names libc puts in the global scope,
because we're never looking for foo in the global scope.

It's obviously better to add our declarations to our own namespace
that we control, not to the global namespace (and an unnamed namespace
at global scope effectively adds the names to the global namespace).



Adding the BEGIN/END_VERSION macros is unnecessary. Those namespaces
are inline, so std::random_device already refers to
std::__8::random_device when the original declaration was in the
versioned namespace.


Ok. I must confess I wasn't clear about this but looking at other src 
files, at least in src/c++11, was showing that it is done almost 
always this way, I guess we could cleanup those files.




The only fix needed here seems to be qualifying std::isdigit (and
strictly-speaking we should also include  to declare that).


Like in attached patch ?


Did you attach the wrong patch?



Indeed, here is the correct one.


diff --git a/libstdc++-v3/src/c++11/random.cc b/libstdc++-v3/src/c++11/random.cc
index 10fbe1dc4c4..04edc582b69 100644
--- a/libstdc++-v3/src/c++11/random.cc
+++ b/libstdc++-v3/src/c++11/random.cc
@@ -41,6 +41,7 @@
 
 #include 
 #include 
+#include  // For std::isdigit.
 
 #if defined _GLIBCXX_HAVE_UNISTD_H && defined _GLIBCXX_HAVE_FCNTL_H
 # include 
@@ -286,7 +287,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
 _M_mt.seed(seed);
 #else
 // Convert old default token "mt19937" or numeric seed tokens to "default".
-if (token == "mt19937" || isdigit((unsigned char)token[0]))
+if (token == "mt19937" || std::isdigit((unsigned char)token[0]))
   _M_init("default");
 else
   _M_init(token);


Re: [PATCH] Fix gnu-versioned-namespace build

2019-12-11 Thread François Dumont

On 12/11/19 12:16 PM, Jonathan Wakely wrote:

On 11/12/19 08:29 +0100, François Dumont wrote:

I plan to commit this tomorrow.

Note that rather than just adding the missing 
_GLIBCXX_[BEGIN,END]_VERSION_NAMESPACE I also move anonymous 
namespace usage outside std namespace. Let me know if it was 
intentional.


It was intentional, why move it?


I just don't get the intention so I proposed to move it. But there are 
indeed other usages of this pattern in other src files.


Note that in src/c++11/debug.cc I am using anonymous namespace at global 
scope, is that wrong ?




Adding the BEGIN/END_VERSION macros is unnecessary. Those namespaces
are inline, so std::random_device already refers to
std::__8::random_device when the original declaration was in the
versioned namespace.


Ok. I must confess I wasn't clear about this but looking at other src 
files, at least in src/c++11, was showing that it is done almost always 
this way, I guess we could cleanup those files.




The only fix needed here seems to be qualifying std::isdigit (and
strictly-speaking we should also include  to declare that).


Like in attached patch ?

I am including it unconditionnaly with other C wrapping headers like 
, is that fine ?


At least it builds fine.




    * src/c++11/random.cc: Add _GLIBCXX_BEGIN_NAMESPACE_VERSION and
    _GLIBCXX_END_NAMESPACE_VERSION. Move anonymous namespace outside std
    namespace.

Tested under Linux x86_64 normal/debug/versioned namespace modes.

There are still tests failing in versioned namespace, more patches to 
come.


François



diff --git a/libstdc++-v3/src/c++11/random.cc 
b/libstdc++-v3/src/c++11/random.cc

index 10fbe1dc4c4..d4ebc9556ab 100644
--- a/libstdc++-v3/src/c++11/random.cc
+++ b/libstdc++-v3/src/c++11/random.cc
@@ -73,8 +73,6 @@
# define USE_MT19937 1
#endif

-namespace std _GLIBCXX_VISIBILITY(default)
-{
namespace
{
#if USE_RDRAND
@@ -124,6 +122,10 @@ namespace std _GLIBCXX_VISIBILITY(default)
#endif
}

+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
  void
  random_device::_M_init(const std::string& token)
  {
@@ -286,7 +288,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
    _M_mt.seed(seed);
#else
    // Convert old default token "mt19937" or numeric seed tokens to 
"default".

-    if (token == "mt19937" || isdigit((unsigned char)token[0]))
+    if (token == "mt19937" || std::isdigit((unsigned char)token[0]))
  _M_init("default");
    else
  _M_init(token);
@@ -407,5 +409,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
    0x9d2c5680UL, 15,
    0xefc6UL, 18, 1812433253UL>;
#endif // USE_MT19937
-}
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
#endif // _GLIBCXX_USE_C99_STDINT_TR1


.



diff --git a/libstdc++-v3/src/c++11/random.cc b/libstdc++-v3/src/c++11/random.cc
index 10fbe1dc4c4..d4ebc9556ab 100644
--- a/libstdc++-v3/src/c++11/random.cc
+++ b/libstdc++-v3/src/c++11/random.cc
@@ -73,8 +73,6 @@
 # define USE_MT19937 1
 #endif
 
-namespace std _GLIBCXX_VISIBILITY(default)
-{
 namespace
 {
 #if USE_RDRAND
@@ -124,6 +122,10 @@ namespace std _GLIBCXX_VISIBILITY(default)
 #endif
 }
 
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
   void
   random_device::_M_init(const std::string& token)
   {
@@ -286,7 +288,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
 _M_mt.seed(seed);
 #else
 // Convert old default token "mt19937" or numeric seed tokens to "default".
-if (token == "mt19937" || isdigit((unsigned char)token[0]))
+if (token == "mt19937" || std::isdigit((unsigned char)token[0]))
   _M_init("default");
 else
   _M_init(token);
@@ -407,5 +409,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
 0x9d2c5680UL, 15,
 0xefc6UL, 18, 1812433253UL>;
 #endif // USE_MT19937
-}
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
 #endif // _GLIBCXX_USE_C99_STDINT_TR1



Re: std::vector code cleanup fixes optimizations

2019-12-15 Thread François Dumont
A small refresh on this patch now tested also for versioned namespace 
which require printers.py to be updated.


Note that this simplification works also for normal mode so I can apply 
it independently from the stl_bvector.h part.



    * include/bits/stl_bvector.h
    [_GLIBCXX_INLINE_VERSION](_Bvector_impl_data::_M_start): Define as
    _Bit_type*.
    (_Bvector_impl_data(const _Bvector_impl_data&)): Default.
    (_Bvector_impl_data(_Bvector_impl_data&&)): Delegate to latter.
    (_Bvector_impl_data::operator=(const _Bvector_impl_data&)): Default.
(_Bvector_impl_data::_M_move_data(_Bvector_impl_data&&)): Use latter.
    (_Bvector_impl_data::_M_reset()): Likewise.
    (_Bvector_impl_data::_M_swap_data): New.
    (_Bvector_impl::_Bvector_impl(_Bvector_impl&&)): Implement explicitely.
    (_Bvector_impl::_Bvector_impl(_Bit_alloc_type&&, _Bvector_impl&&)): 
New.

    (_Bvector_base::_Bvector_base(_Bvector_base&&, const allocator_type&)):
    New, use latter.
    (vector::vector(vector&&, const allocator_type&, true_type)): New, use
    latter.
    (vector::vector(vector&&, const allocator_type&, false_type)): New.
    (vector::vector(vector&&, const allocator_type&)): Use latters.
    (vector::vector(const vector&, const allocator_type&)): Adapt.
    [__cplusplus >= 201103](vector::vector(_InputIt, _InputIt,
    const allocator_type&)): Use _M_initialize_range.
    (vector::operator[](size_type)): Use iterator operator[].
    (vector::operator[](size_type) const): Use const_iterator operator[].
    (vector::swap(vector&)): Add assertions on allocators. Use 
_M_swap_data.

    [__cplusplus >= 201103](vector::insert(const_iterator, _InputIt,
    _InputIt)): Use _M_insert_range.
    (vector::_M_initialize(size_type)): Adapt.
    [__cplusplus >= 201103](vector::_M_initialize_dispatch): Remove.
    [__cplusplus >= 201103](vector::_M_insert_dispatch): Remove.
    * python/libstdcxx/v6/printers.py (StdVectorPrinter._iterator): Stop
    using start _M_offset.
    (StdVectorPrinter.to_string): Likewise.
    * testsuite/23_containers/vector/bool/allocator/swap.cc: Adapt.
    * testsuite/23_containers/vector/bool/cons/noexcept_move_construct.cc:
    Add check.

François


On 6/24/19 9:31 PM, François Dumont wrote:

Hi

    Any feedback regarding this patch ?

Thanks

On 5/14/19 7:46 AM, François Dumont wrote:

Hi

    This is the patch on vector to:

- Optimize sizeof in Versioned namespace mode. We could go one step 
further by removing _M_p from _M_finish and just transform it into an 
offset but it is a little bit more impacting for the code.


- Implement the swap optimization already done on main std::vector 
template class.


- Fix move constructor so that it is noexcept no matter allocator 
move constructor noexcept qualification


- Optimize move constructor with allocator when allocator type is 
always equal.


- Use shortcuts in C++11 by skipping the _M_XXX_dispatch methods. 
Those are now defined only in pre-C++11 mode, I can't see any abi 
issue in doing so.


    * include/bits/stl_bvector.h
    [_GLIBCXX_INLINE_VERSION](_Bvector_impl_data::_M_start): Define as
    _Bit_type*.
    (_Bvector_impl_data(const _Bvector_impl_data&)): Default.
    (_Bvector_impl_data(_Bvector_impl_data&&)): Delegate to latter.
    (_Bvector_impl_data::operator=(const _Bvector_impl_data&)): Default.
(_Bvector_impl_data::_M_move_data(_Bvector_impl_data&&)): Use latter.
    (_Bvector_impl_data::_M_reset()): Likewise.
    (_Bvector_impl_data::_M_swap_data): New.
    (_Bvector_impl::_Bvector_impl(_Bvector_impl&&)): Implement 
explicitely.
    (_Bvector_impl::_Bvector_impl(_Bit_alloc_type&&, 
_Bvector_impl&&)): New.
    (_Bvector_base::_Bvector_base(_Bvector_base&&, const 
allocator_type&)):

    New, use latter.
    (vector::vector(vector&&, const allocator_type&, true_type)): 
New, use

    latter.
    (vector::vector(vector&&, const allocator_type&, false_type)): New.
    (vector::vector(vector&&, const allocator_type&)): Use latters.
    (vector::vector(const vector&, const allocator_type&)): Adapt.
    [__cplusplus >= 201103](vector::vector(_InputIt, _InputIt,
    const allocator_type&)): Use _M_initialize_range.
    (vector::operator[](size_type)): Use iterator operator[].
    (vector::operator[](size_type) const): Use const_iterator 
operator[].

    (vector::swap(vector&)): Adapt.
    (vector::_M_initialize(size_type)): Add assertions on allocators.
    Use _M_swap_data.
    [__cplusplus >= 201103](vector::insert(const_iterator, _InputIt,
    _InputIt)): Use _M_insert_range.
    [__cplusplus >= 201103](vector::_M_initialize_dispatch): Remove.
    [__cplusplus >= 201103](vector::_M_insert_dispatch): Remove.
    * testsuite/23_containers/vector/bool/allocator/swap.cc: Adapt.
  

Re: [PATCH] Help compiler detect invalid code

2019-10-16 Thread François Dumont

Here is a version with __detail::__copy and __detail::__copy_backward.

I prefered to introduce the __detail namespace cause __copy is quite a 
common name so putting it in __detail namespace will I hope clarify that 
it is for internal usage only.


I even hesitated to put more details into this namespace, maybe for 
another patch later.


    * include/bits/stl_algobase.h (__memmove): Replace by...
    (__detail::__copy) ...that. Return void, loop as long as __n != 0.
    (__copy_move<_IsMove, true, 
std::random_access_iterator_tag>::__copy_m):

    Adapt to use latter.
    (__detail::__copy_backward): New.
    (__copy_move_backward<_IsMove, true,
    std::random_access_iterator_tag>::__copy_m): Adapt to use latter.
    (__copy_move_backward_a): Remove std::is_constant_evaluated block.
    * testsuite/25_algorithms/copy/constexpr.cc (test): Add check on copied
    values.
    * testsuite/25_algorithms/copy_backward/constexpr.cc (test): Likewise
    and rename in test1.
    (test2): New.
    * testsuite/25_algorithms/copy/constexpr_neg.cc: New.
    * testsuite/25_algorithms/copy_backward/constexpr.cc: New.
    * testsuite/25_algorithms/equal/constexpr_neg.cc: New.
    * testsuite/25_algorithms/move/constexpr.cc: New.
    * testsuite/25_algorithms/move/constexpr_neg.cc: New.

François

On 10/10/19 10:03 PM, Jonathan Wakely wrote:

On 01/10/19 22:05 +0200, François Dumont wrote:

On 9/27/19 1:24 PM, Jonathan Wakely wrote:

On 20/09/19 07:08 +0200, François Dumont wrote:
I already realized that previous patch will be too controversial to 
be accepted.


In this new version I just implement a real memmove in __memmove so


A real memmove doesn't just work backwards, it needs to detect any
overlaps and work forwards *or* backwards, as needed.
ok, good to know, I understand now why using __builtin_memcopy didn't 
show any performance enhancement when I tested it !


I think your change will break this case:

#include 

constexpr int f(int i, int j, int k)
{
 int arr[5] = { 0, 0, i, j, k };
 std::move(arr+2, arr+5, arr);
 return arr[0] + arr[1] + arr[2];
}

static_assert( f(1, 2, 3) == 6 );

This is valid because std::move only requires that the result iterator
is not in the input range, but it's OK for the two ranges to overlap.

I haven't tested it, but I think with your change the array will end
up containing {3, 2, 3, 2, 3} instead of {1, 2, 3, 2, 3}.

Indeed, I've added a std::move constexpr test in this new proposal 
which demonstrate that.


C++ Standard clearly states that [copy|move]_backward is done 
backward. So in this new proposal I propose to add a __memcopy used 
in copy/move and keep __memmove for *_backward algos. Both are using 
__builtin_memmove as before.


Then they *really* need better names now (__memmove was already a bad
name, but now it's terrible). If the difference is that one goes
forwards and one goes backwards, the names should reflect that.

I'll review it properly tomorrow.




diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 98d324827ed..dc6b3d3fc76 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -77,19 +77,22 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+namespace __detail
+{
   /*
* A constexpr wrapper for __builtin_memmove.
+   * When constant-evaluated performs a forward copy.
* @param __num The number of elements of type _Tp (not bytes).
*/
   template
 _GLIBCXX14_CONSTEXPR
-inline void*
-__memmove(_Tp* __dst, const _Tp* __src, size_t __num)
+inline void
+__copy(_Tp* __dst, const _Tp* __src, ptrdiff_t __num)
 {
 #ifdef __cpp_lib_is_constant_evaluated
   if (std::is_constant_evaluated())
 	{
-	  for(; __num > 0; --__num)
+	  for (; __num != 0; --__num)
 	{
 	  if constexpr (_IsMove)
 		*__dst = std::move(*__src);
@@ -98,13 +101,40 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  ++__src;
 	  ++__dst;
 	}
-	  return __dst;
 	}
   else
 #endif
-	return __builtin_memmove(__dst, __src, sizeof(_Tp) * __num);
-  return __dst;
+	__builtin_memmove(__dst, __src, sizeof(_Tp) * __num);
+}
+
+  /*
+   * A constexpr wrapper for __builtin_memmove.
+   * When constant-evaluated performs a backward copy.
+   * @param __num The number of elements of type _Tp (not bytes).
+   */
+  template
+_GLIBCXX14_CONSTEXPR
+inline void
+__copy_backward(_Tp* __dst, const _Tp* __src, ptrdiff_t __num)
+{
+#ifdef __cpp_lib_is_constant_evaluated
+  if (std::is_constant_evaluated())
+	{
+	  __dst += __num;
+	  __src += __num;
+	  for (; __num != 0; --__num)
+	{
+	  if constexpr (_IsMove)
+		*--__dst = std::move(*--__src);
+	  else
+		*--__dst = *--__src;
+	}
+	}
+  else
+#endif
+	__builtin_memmove(__dst, __src, sizeof(_Tp) * __num);
 }
+} // namespace __detail
 
   /*
* A constexpr wrapper for __builtin_memcmp.
@

[PATCH] ostreambuf_iterator std::advance overload

2019-10-15 Thread François Dumont

Hi

    I completed this overload before noticing that the Standard do not 
expect anything when 'advancing' an output iterator.


    But as I've done it consistenly with the istreambuf_iterator here 
it is with samples about how to use it.


    Let me know if acceptable.

François

diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h b/libstdc++-v3/include/bits/streambuf_iterator.h
index 17dd3972d45..76ba96d634a 100644
--- a/libstdc++-v3/include/bits/streambuf_iterator.h
+++ b/libstdc++-v3/include/bits/streambuf_iterator.h
@@ -242,6 +242,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	copy(istreambuf_iterator<_CharT2>, istreambuf_iterator<_CharT2>,
 	 ostreambuf_iterator<_CharT2>);
 
+  template
+	friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
+	   void>::__type
+	advance(ostreambuf_iterator<_CharT2>&, _Distance);
+
 private:
   streambuf_type*	_M_sbuf;
   bool		_M_failed;
@@ -453,6 +458,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 }
 
+  template
+typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
+void>::__type
+advance(ostreambuf_iterator<_CharT>& __i, _Distance __n)
+{
+  if (__n == 0)
+	return;
+
+  __glibcxx_assert(__n > 0);
+  __glibcxx_requires_cond(!__i.failed(),
+			  _M_message(__gnu_debug::__msg_advance_oob)
+			  ._M_iterator(__i)
+			  ._M_integer(__n));
+
+  typedef basic_streambuf<_CharT> __streambuf_t;
+  typedef typename __streambuf_t::pos_type __pos_t;
+  __pos_t __cur_pos
+	= __i._M_sbuf->pubseekoff(0, ios_base::cur, ios_base::out);
+  __pos_t __new_pos =
+	__i._M_sbuf->pubseekoff(__n, ios_base::cur, ios_base::out);
+
+  if (__new_pos - __cur_pos != __n)
+	{
+	  __i._M_failed = true;
+	  __glibcxx_requires_cond(!__i.failed(),
+  _M_message(__gnu_debug::__msg_advance_oob)
+  ._M_iterator(__i)
+  ._M_integer(__n));
+	}
+}
+
 // @} group iterators
 
 _GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/testsuite/25_algorithms/advance/ostreambuf_iterator/char/1.cc b/libstdc++-v3/testsuite/25_algorithms/advance/ostreambuf_iterator/char/1.cc
new file mode 100644
index 000..15cf0b27863
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/advance/ostreambuf_iterator/char/1.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2019 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
+// .
+
+#include 
+#include 
+#include 
+
+#include 
+
+void test01()
+{
+  using namespace std;
+
+  const char data1[] = "Drei Phantasien nach Friedrich Holderlin";
+  string str1(data1);
+  str1[17] = 'i';
+
+  ostringstream oss1(str1);
+  ostreambuf_iterator beg1(oss1);
+
+  std::advance(beg1, 17);
+  *beg1 = 'a';
+
+  VERIFY( !beg1.failed() );
+  VERIFY( oss1.str() == data1 );
+  str1 = oss1.str();
+
+  // -1 for the trailing '\0'
+  // -1 for the beg1 assignment.
+  std::advance(beg1, sizeof(data1) - 17 - 1 - 1);
+  *beg1 = '.';
+
+  str1 += '.';
+  VERIFY( oss1.str() == str1 );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/advance/ostreambuf_iterator/char/1_neg.cc b/libstdc++-v3/testsuite/25_algorithms/advance/ostreambuf_iterator/char/1_neg.cc
new file mode 100644
index 000..9d1e4a94742
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/advance/ostreambuf_iterator/char/1_neg.cc
@@ -0,0 +1,40 @@
+// Copyright (C) 2019 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
+// .
+
+// { dg-do run { xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include 
+#include 
+#include 
+
+void test01()
+{
+  using namespace std;
+
+  const char 

Re: [PATCH] Implement std::advance for istreambuf_iterator using pubseekoff

2019-10-15 Thread François Dumont

Here is an update to set _M_sbuf to null if the user advance too much.

Note that in this case the streambuf remains un-modified which is 
different from the current implementation. I think it is another 
enhancement.


I also change the Debug assertion message for something more dedicated 
to std::advance algo.


François

On 10/14/19 10:12 PM, François Dumont wrote:
The same way I proposed to review std::copy overload for 
istreambuf_iterator we can implement std::advance using pubseekoff.


It is both a cleaner implementation and avoids yet another friend 
declaration.



    * include/std/streambuf
    (advance(istreambuf_iterator<>&, _Distance)): Remove friend 
declaration.
    * include/bits/streambuf_iterator.h (__copy_move_a2): Re-implement 
using

    streambuf pubseekoff.

Tested under Linux x86_64.

Ok to commit ?

François



diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h b/libstdc++-v3/include/bits/streambuf_iterator.h
index 134b3486b9a..17dd3972d45 100644
--- a/libstdc++-v3/include/bits/streambuf_iterator.h
+++ b/libstdc++-v3/include/bits/streambuf_iterator.h
@@ -431,37 +431,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   __glibcxx_assert(__n > 0);
   __glibcxx_requires_cond(!__i._M_at_eof(),
-			  _M_message(__gnu_debug::__msg_inc_istreambuf)
-			  ._M_iterator(__i));
-
-  typedef istreambuf_iterator<_CharT>		   __is_iterator_type;
-  typedef typename __is_iterator_type::traits_type	   traits_type;
-  typedef typename __is_iterator_type::streambuf_type  streambuf_type;
-  typedef typename traits_type::int_type		   int_type;
-  const int_type __eof = traits_type::eof();
-
-  streambuf_type* __sb = __i._M_sbuf;
-  while (__n > 0)
-	{
-	  streamsize __size = __sb->egptr() - __sb->gptr();
-	  if (__size > __n)
+			  _M_message(__gnu_debug::__msg_advance_oob)
+			  ._M_iterator(__i)
+			  ._M_integer(__n));
+
+  typedef basic_streambuf<_CharT> __streambuf_t;
+  typedef typename __streambuf_t::pos_type __pos_t;
+  __pos_t __cur_pos
+	= __i._M_sbuf->pubseekoff(0, ios_base::cur, ios_base::in);
+  __pos_t __new_pos
+	= __i._M_sbuf->pubseekoff(__n, ios_base::cur, ios_base::in);
+  __i._M_c = char_traits<_CharT>::eof();
+
+  if (__new_pos - __cur_pos != __n)
 	{
-	  __sb->__safe_gbump(__n);
-	  break;
-	}
-
-	  __sb->__safe_gbump(__size);
-	  __n -= __size;
-	  if (traits_type::eq_int_type(__sb->underflow(), __eof))
-	{
-	  __glibcxx_requires_cond(__n == 0,
-_M_message(__gnu_debug::__msg_inc_istreambuf)
-._M_iterator(__i));
-	  break;
-	}
+	  __i._M_sbuf = 0;
+	  __glibcxx_requires_cond(!__i._M_at_eof(),
+  _M_message(__gnu_debug::__msg_advance_oob)
+  ._M_iterator(__i)
+  ._M_integer(__n));
 	}
-
-  __i._M_c = __eof;
 }
 
 // @} group iterators
diff --git a/libstdc++-v3/include/std/streambuf b/libstdc++-v3/include/std/streambuf
index 3442f19bd78..ef03da39bc2 100644
--- a/libstdc++-v3/include/std/streambuf
+++ b/libstdc++-v3/include/std/streambuf
@@ -155,11 +155,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 find(istreambuf_iterator<_CharT2>, istreambuf_iterator<_CharT2>,
 	 const _CharT2&);
 
-  template
-friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
-	   void>::__type
-advance(istreambuf_iterator<_CharT2>&, _Distance);
-
   template
 friend basic_istream<_CharT2, _Traits2>&
 operator>>(basic_istream<_CharT2, _Traits2>&, _CharT2*);
diff --git a/libstdc++-v3/testsuite/25_algorithms/advance/istreambuf_iterators/char/3.cc b/libstdc++-v3/testsuite/25_algorithms/advance/istreambuf_iterators/char/3.cc
new file mode 100644
index 000..8763e7fa78e
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/advance/istreambuf_iterators/char/3.cc
@@ -0,0 +1,49 @@
+// Copyright (C) 2017-2019 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/>.
+
+// Debug mode would detect the invalid std::advance call.
+// { dg-require-normal-mode "" }
+
+#include 
+#include 
+#include 
+
+#include 
+
+void test01()
+{
+  using namespace std;
+
+  typedef istreambuf_iterator in_iterat

[PATCH] Clarify constness and state

2019-10-15 Thread François Dumont

    * src/c++11/debug.cc (print_field): Replace constness_names 
    entry with . Replace state_names  entry 
with

    .

Committed as trivial.

François

Index: src/c++11/debug.cc
===
--- src/c++11/debug.cc	(révision 277048)
+++ src/c++11/debug.cc	(copie de travail)
@@ -721,7 +721,7 @@
 	static const char*
 	  constness_names[_Error_formatter::__last_constness] =
 	  {
-		"",
+		"",
 		"constant",
 		"mutable"
 	  };
@@ -732,7 +732,7 @@
 	static const char*
 	  state_names[_Error_formatter::__last_state] =
 	  {
-		"",
+		"",
 		"singular",
 		"dereferenceable (start-of-sequence)",
 		"dereferenceable",


Re: [PATCH, libstdc++] More

2019-11-25 Thread François Dumont
I have a patch for the same location so here is my remark that might 
make my patch useless.


Maybe you can even merge it with yours Ed, here it is:

https://gcc.gnu.org/ml/libstdc++/2019-10/msg00072.html

On 11/25/19 10:15 PM, Jonathan Wakely wrote:

On 15/11/19 22:17 -0500, Ed Smith-Rowland via libstdc++ wrote:

Index: include/bits/stl_algobase.h
===
--- include/bits/stl_algobase.h    (revision 278318)
+++ include/bits/stl_algobase.h    (working copy)
@@ -107,6 +107,50 @@
    }

  /*
+   * A constexpr wrapper for __builtin_memmove.


This should say __builtin_memcpy.


+   * @param __num The number of elements of type _Tp (not bytes).
+   */
+  template
+    _GLIBCXX14_CONSTEXPR
+    inline void*
+    __memcpy(_Tp* __dst, const _Tp* __src, size_t __num)
+    {
+#ifdef __cpp_lib_is_constant_evaluated
+  if (std::is_constant_evaluated())
+    {
+  for(; __num > 0; --__num)


for (; __num != 0; --__num)

and make __num prtdiff_t.

would be better here as this way the compiler is able to report bad 
usages rather than silently do nothing.




+    *__dst++ = *__src++;
+  return __dst;
+    }
+  else
+#endif
+    return __builtin_memcpy(__dst, __src, sizeof(_Tp) * __num);
+  return __dst;
+    }
+
+  /*
+   * A constexpr wrapper for __builtin_memmove.


And this should say __builtin_memset.


+   * @param __num The number of elements of type _Tp (not bytes).
+   */
+  template
+    _GLIBCXX14_CONSTEXPR
+    inline void*
+    __memset(_Tp* __dst, _Tp __a, size_t __num)
+    {
+#ifdef __cpp_lib_is_constant_evaluated
+  if (std::is_constant_evaluated())
+    {
+  for(; __num > 0; --__num)
+    *__dst = __a;
+  return __dst;
+    }
+  else
+#endif
+    return __builtin_memset(__dst, __a, sizeof(_Tp) * __num);
+  return __dst;
+    }


OK for trunk with those two comment fixes. Thanks.







Re: [PATCH][_GLIBCXX_DEBUG] Improve valid_range check

2019-11-26 Thread François Dumont

On 11/26/19 1:21 PM, Jonathan Wakely wrote:

On 26/11/19 12:33 +0100, Stephan Bergmann wrote:

On 22/11/2019 18:59, Jonathan Wakely wrote:

On 22/11/19 18:38 +0100, François Dumont wrote:
    I noticed that we are not checking that iterators are not 
singular in valid_range. Moreover __check_singular signature for 
pointers is not intercepting all kind of pointers in terms of 
qualification.


    I'd like to commit it next week but considering we are in stage 
3 I need proper acceptance.


    * include/debug/functions.h: Remove  include.
    (__check_singular_aux, __check_singular): Move...
    * include/debug/helper_functions.h:
    (__check_singular_aux, __check_singular): ...here.
    (__valid_range_aux): Adapt to use latter.
    * testsuite/25_algorithms/copy/debug/2_neg.cc: New.

Tested under Linux x86_64 normal and debug modes.


OK for trunk, thanks.


The curly braces...

diff --git a/libstdc++-v3/include/debug/helper_functions.h 
b/libstdc++-v3/include/debug/helper_functions.h

index c3e7478f649..5a858754875 100644
--- a/libstdc++-v3/include/debug/helper_functions.h
+++ b/libstdc++-v3/include/debug/helper_functions.h

[...]

@@ -138,14 +156,23 @@ namespace __gnu_debug
    inline bool
    __valid_range_aux(_InputIterator __first, _InputIterator __last,
  std::input_iterator_tag)
-    { return true; }
+    {
+  if (__first != __last)
+    return !__check_singular(__first) && !__check_singular(__last);
+
+  return true;
+    }
  template
    _GLIBCXX_CONSTEXPR
    inline bool
    __valid_range_aux(_InputIterator __first, _InputIterator __last,
  std::random_access_iterator_tag)
-    { return __first <= __last; }
+    {
+  return
+    __valid_range_aux(__first, __last, std::input_iterator_tag{})


...^^^ here...


+    && __first <= __last;
+    }
  /** We have iterators, so figure out what kind of iterators they are
   *  to see if we can check the range ahead of time.
@@ -167,6 +194,9 @@ namespace __gnu_debug
  typename _Distance_traits<_InputIterator>::__type& 
__dist,

  std::__false_type)
    {
+  if (!__valid_range_aux(__first, __last, 
std::input_iterator_tag{}))


...and ^^^ here are not allowed pre C++11.  Replacing those with

 std::input_iterator_tag()

should fix it.


Indeed. We should also have tests that use "-std=gnu++98
-D_GLIBCXX_DEBUG" so they'd catch this.

François, can you take care of the fix please?




Sure, I am about to do so.

However I wasn't sure about this syntax before the commit so I had run 
the new 2_neg.cc with:


make CXXFLAGS=-std=c++98 check-debug

and it worked fine and still is !

I also try -std=gnu++98 and made sure that pch had been updated by 
re-building libstdc++ first. I just can't get the expected compilation 
error.


Maybe I need to rebuild the whole stuff to get an error...

Sorry



Re: [PATCH][_GLIBCXX_DEBUG] Improve valid_range check

2019-11-26 Thread François Dumont

On 11/26/19 9:49 PM, Stephan Bergmann wrote:

On 26/11/2019 20:07, François Dumont wrote:
However I wasn't sure about this syntax before the commit so I had 
run the new 2_neg.cc with:


make CXXFLAGS=-std=c++98 check-debug

and it worked fine and still is !

I also try -std=gnu++98 and made sure that pch had been updated by 
re-building libstdc++ first. I just can't get the expected 
compilation error.


Maybe I need to rebuild the whole stuff to get an error...


I saw the error with recent Clang and -std=gnu++98.  Recent GCC indeed 
seems to give at most a warning.




Ok, thanks for the feedback, gcc might be more permissive then.

Whatever I committed the fix an hour ago.



Re: [PATCH][_GLIBCXX_DEBUG] Improve valid_range check

2019-11-26 Thread François Dumont

On 11/26/19 10:52 PM, Jonathan Wakely wrote:

On 26/11/19 20:07 +0100, François Dumont wrote:

Sure, I am about to do so.

However I wasn't sure about this syntax before the commit so I had 
run the new 2_neg.cc with:


make CXXFLAGS=-std=c++98 check-debug

and it worked fine and still is !


The testsuite doesn't use CXXFLAGS.


Did you mean CPPFLAGS ?

I do see the option added to the compiler call in libstdc++.log file. 
And I used it to build for instance pretty-printers tests in 
_GLIBCXX_DEBUG mode with success.




I also try -std=gnu++98 and made sure that pch had been updated by 
re-building libstdc++ first. I just can't get the expected 
compilation error.


Maybe I need to rebuild the whole stuff to get an error...


No, you need to pass the right flags so they are used by the
testsuite. This will do it:

make -C testsuite/  check-debug 
debug_flags=unix/-D_GLIBCXX_DEBUG/-std=gnu++98/-Wsystem-headers

I'll have to keep your mail to remember it !


But since it only shows up with -Wsystem-headers, there's no point
trying to test for it.



Ok, makes sens.

Thanks



[PATCH] Enhance _GLIBCXX_DEBUG constexpr support

2019-12-02 Thread François Dumont

Hi

    Here is a patch to enhance constexpr support in _GLIBCXX_DEBUG. I 
work on std::lower_bound/upper_bound to find out if Debug mode is well 
prepared. I'll continue on other algos later.


    I initially hope that I could count on the compiler for the 
valid_range check. But for lower_bound/upper_bound there is no constexpr 
dedicated implementation like for copy/copy_backward so it implies 
changing the existing implementation. So I tried to change the 
while(__len > 0) into a while(__len != 0) and it gave:


constexpr_valid_range_neg.cc:35:20: error: non-constant condition for 
static assertion

   35 | static_assert(test1()); // { dg-error "" }
  |   ~^~
In file included from 
/home/fdt/dev/gcc/install/include/c++/10.0.0/algorithm:61,

 from constexpr_valid_range_neg.cc:22:
constexpr_valid_range_neg.cc:35:20:   in ‘constexpr’ expansion of ‘test1()’
constexpr_valid_range_neg.cc:30:38:   in ‘constexpr’ expansion of 
‘std::lower_bound(ca0.std::array::end(), 
ca0.std::array::begin(), 6)’
/home/fdt/dev/gcc/install/include/c++/10.0.0/bits/stl_algobase.h:1484:32: 
in ‘constexpr’ expansion of ‘std::__lower_bound__gnu_cxx::__ops::_Iter_less_val>(__first, __last, (* & __val), 
__gnu_cxx::__ops::__iter_less_val())’
/home/fdt/dev/gcc/install/include/c++/10.0.0/bits/stl_algobase.h:1444:7: 
error: ‘constexpr’ loop iteration count exceeds limit of 262144 (use 
‘-fconstexpr-loop-limit=’ to increase the limit)

 1444 |   while (__len != 0)
  |   ^

    It seems ok but it isn't. The compiler had to loop 262144 times to 
eventually give this status which is not even clear about the fact that 
begin/end has been inverted. It is a quite heavy operation for a limited 
result.


    So this patch rather enable _GLIBCXX_DEBUG valid_range check which 
gives:


constexpr_valid_range_neg.cc:35:20: error: non-constant condition for 
static assertion

   35 | static_assert(test1()); // { dg-error "" }
  |   ~^~
In file included from 
/home/fdt/dev/gcc/install/include/c++/10.0.0/debug/debug.h:90,
 from 
/home/fdt/dev/gcc/install/include/c++/10.0.0/bits/stl_algobase.h:69,
 from 
/home/fdt/dev/gcc/install/include/c++/10.0.0/algorithm:61,

 from constexpr_valid_range_neg.cc:22:
constexpr_valid_range_neg.cc:35:20:   in ‘constexpr’ expansion of ‘test1()’
constexpr_valid_range_neg.cc:30:38:   in ‘constexpr’ expansion of 
‘std::lower_bound(ca0.std::__debug::array12>::end(), ca0.std::__debug::array::begin(), 6)’
/home/fdt/dev/gcc/install/include/c++/10.0.0/bits/stl_algobase.h:1482:7: 
error: inline assembly is not a constant expression

 1482 |   __glibcxx_requires_partitioned_lower(__first, __last, __val);
  |   ^~~~
/home/fdt/dev/gcc/install/include/c++/10.0.0/bits/stl_algobase.h:1482:7: 
note: only unevaluated inline assembly is allowed in a ‘constexpr’ 
function in C++2a


This time it is done in no time. Of course you can see that the asm 
trick to generate a non-constant condition is not so nice.


We just don't see the asm call parameter but showing 
__glibcxx_requires_partitioned_lower is not so bad. For this reason the 
tests in this patch are not checking for any failure message. We'll see 
how to adapt when we have the necessary front end help to generate this 
compilation error.


Of course I could have a nicer compilation error by directly calling 
__glibcxx_requires_valid_range in the algo and stop doing it within 
__glibcxx_requires_partitioned_lower. Do you want to expose all macros 
this way ?



    * include/debug/formatter.h (__check_singular): Add C++11 constexpr
    qualification.
    * include/debug/helper_functions.h (__check_singular): Likewise. Skip
    check if constant evaluated.
    (__valid_range): Remove check skip if constant evaluated.
    * include/debug/macros.h [_GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED]
    (_GLIBCXX_DEBUG_VERIFY_COND_AT): Define.
    * testsuite/25_algorithms/lower_bound/constexpr.cc (test): Add 
checks on

    lower_bound results.
    * testsuite/25_algorithms/upper_bound/constexpr.cc (test): Likewise.
    * testsuite/25_algorithms/lower_bound/debug/
    constexpr_partitioned_neg.cc: New.
    * testsuite/25_algorithms/lower_bound/debug/
    constexpr_partitioned_pred_neg.cc: New.
    * testsuite/25_algorithms/lower_bound/debug/
    constexpr_valid_range_neg.cc: New.
    * testsuite/25_algorithms/lower_bound/debug/partitioned_neg.cc: New.
    * testsuite/25_algorithms/lower_bound/debug/partitioned_pred_neg.cc:
    New.
    * testsuite/25_algorithms/upper_bound/debug/
    constexpr_partitioned_neg.cc: New.
    * testsuite/25_algorithms/upper_bound/debug/
    constexpr_partitioned_pred_neg.cc: New.
    * testsuite/25_algorithms/upper_bound/debug/
    constexpr_valid_range_neg.cc: New.
    * testsuite/25_algorithms/upper_bound/debug/partitioned_neg.cc: New.
    * 

[PATCH] C++20 P1032 for __debug::array

2019-11-25 Thread François Dumont

I plan to commit this tomorrow.

But I really wonder if we couldn't just add some __glibcxx_checks_xxx in 
std/array ?


    * include/debug/array (array<>::fill): Add C++20 constexpr.
    (array<>::swap): Likewise.

François

diff --git a/libstdc++-v3/include/debug/array b/libstdc++-v3/include/debug/array
index 5566a087f9a..4e0fac8daac 100644
--- a/libstdc++-v3/include/debug/array
+++ b/libstdc++-v3/include/debug/array
@@ -80,11 +80,11 @@ namespace __debug
   // No explicit construct/copy/destroy for aggregate type.
 
   // DR 776.
-  void
+  _GLIBCXX20_CONSTEXPR void
   fill(const value_type& __u)
   { std::fill_n(begin(), size(), __u); }
 
-  void
+  _GLIBCXX20_CONSTEXPR void
   swap(array& __other)
   noexcept(_AT_Type::_Is_nothrow_swappable::value)
   { std::swap_ranges(begin(), end(), __other.begin()); }
@@ -282,6 +282,7 @@ namespace __debug
 #endif
 
   template
+_GLIBCXX20_CONSTEXPR
 inline void
 swap(array<_Tp, _Nm>& __one, array<_Tp, _Nm>& __two)
 noexcept(noexcept(__one.swap(__two)))


[PATCH] Add safe iterator iterator_concept

2019-11-25 Thread François Dumont

I plan to commit this patch tomorrow.

    * include/debug/safe_iterator.h
[__cpp_lib_concepts](_Safe_iterator<>::iterator_concept): Define for
    C++20.

François

diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
index 685256551d9..abf575186c7 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -141,6 +141,10 @@ namespace __gnu_debug
   typedef typename _Traits::reference		reference;
   typedef typename _Traits::pointer			pointer;
 
+#if __cplusplus > 201703L && __cpp_lib_concepts
+  using iterator_concept = std::__detail::__iter_concept<_Iterator>;
+#endif
+
   /// @post the iterator is singular and unattached
   _Safe_iterator() _GLIBCXX_NOEXCEPT : _Iter_base() { }
 


Re: copy/copy_backward/fill/fill_n/equal rework

2019-09-24 Thread François Dumont

Ping ?

On 9/9/19 8:34 PM, François Dumont wrote:

Hi

    This patch improves stl_algobase.h 
copy/copy_backward/fill/fill_n/equal implementations. The improvements 
are:


- activation of algo specialization for __gnu_debug::_Safe_iterator 
(w/o _GLIBCXX_DEBUG mode)


- activation of algo specialization for _Deque_iterator even if mixed 
with another kind of iterator.


- activation of algo specializations __copy_move_a2 for something else 
than pointers. For example this code:


std::vector v { 'a', 'b',  };

ostreambuf_iterator out(std::cout);

std::copy(v.begin(), v.end(), out);

is not calling the specialization __copy_move_a2(const char*, const 
char*, ostreambuf_iterator<>);


It also fix a _GLIBCXX_DEBUG issue where the __niter_base 
specialization was wrongly removing the _Safe_iterator<> layer. The 
testsuite/25_algorithms/copy/debug/1_neg.cc test case was failing on a 
debug assertion because _after_ the copy we were trying to increment 
the vector iterator after past-the-end. Of course the problem is the 
_after_, Debug mode should detect this _before_ it takes place which 
it does now.


Note that std::fill_n is now making use of std::fill for some 
optimizations dealing with random access iterators.


Performances are very good:

Before:

copy_backward_deque_iterators.cc    deque 2 deque 1084r 1084u 
0s 0mem    0pf
copy_backward_deque_iterators.cc    deque 2 vector 3373r 3372u 
0s 0mem    0pf
copy_backward_deque_iterators.cc    vector 2 deque 3316r 3316u 
0s 0mem    0pf
copy_backward_deque_iterators.cc    int deque 2 char vector 3610r 
3609u    0s 0mem    0pf
copy_backward_deque_iterators.cc    char vector 2 int deque 3552r 
3552u    0s 0mem    0pf
copy_backward_deque_iterators.cc    deque 2 list 10528r 10528u 
0s 0mem    0pf
copy_backward_deque_iterators.cc    list 2 deque 2161r 2162u 
0s 0mem    0pf
copy_deque_iterators.cc      deque 2 deque         752r 
751u    0s 0mem    0pf
copy_deque_iterators.cc      deque 2 vector       3300r 
3299u    0s 0mem    0pf
copy_deque_iterators.cc      vector 2 deque       3144r 
3140u    0s 0mem    0pf
copy_deque_iterators.cc      int deque 2 char vector      3340r 
3338u    1s 0mem    0pf
copy_deque_iterators.cc      char vector 2 int deque      3132r 
3132u    0s 0mem    0pf
copy_deque_iterators.cc      deque 2 list     10013r 
10012u    0s 0mem    0pf
copy_deque_iterators.cc      list 2 deque     2274r 
2275u    0s 0mem    0pf
equal_deque_iterators.cc     deque vs deque       8676r 
8675u    0s 0mem    0pf
equal_deque_iterators.cc     deque vs vector      5870r 
5870u    0s 0mem    0pf
equal_deque_iterators.cc     vector vs deque      3163r 
3163u    0s 0mem    0pf
equal_deque_iterators.cc     int deque vs char vector     5845r 
5845u    0s 0mem    0pf
equal_deque_iterators.cc     char vector vs int deque     3307r 
3307u    0s 0mem    0pf


After:

copy_backward_deque_iterators.cc    deque 2 deque  697r  697u 
0s 0mem    0pf
copy_backward_deque_iterators.cc    deque 2 vector  219r  218u 
0s 0mem    0pf
copy_backward_deque_iterators.cc    vector 2 deque  453r  453u 
0s 0mem    0pf
copy_backward_deque_iterators.cc    int deque 2 char vector 1914r 
1915u    0s 0mem    0pf
copy_backward_deque_iterators.cc    char vector 2 int deque 2112r 
2111u    0s 0mem    0pf
copy_backward_deque_iterators.cc    deque 2 list 7770r 7771u 
0s 0mem    0pf
copy_backward_deque_iterators.cc    list 2 deque 2194r 2193u 
0s 0mem    0pf
copy_deque_iterators.cc      deque 2 deque         505r 
504u    0s 0mem    0pf
copy_deque_iterators.cc      deque 2 vector        221r 
221u    0s 0mem    0pf
copy_deque_iterators.cc      vector 2 deque        398r 
397u    0s 0mem    0pf
copy_deque_iterators.cc      int deque 2 char vector      1770r 
1767u    0s 0mem    0pf
copy_deque_iterators.cc      char vector 2 int deque      1995r 
1993u    0s 0mem    0pf
copy_deque_iterators.cc      deque 2 list     7650r 
7641u    2s 0mem    0pf
copy_deque_iterators.cc      list 2 deque     2270r 
2270u    0s 0mem    0pf
equal_deque_iterators.cc     deque vs deque        769r 
768u    0s 0mem    0pf
equal_deque_iterators.cc     deque vs vector       231r 
230u    0s 0mem    0pf
equal_deque_iterators.cc     vector vs deque       397r 
397u    0s 0mem    0pf
equal_deque_iterators.cc     int deque vs char vector     1541r 
1541u    0s 0mem    0pf
equal_deque_iterators.cc     char vector vs int deque     1623r 
1623u    0s 0mem    0pf


In Debug Mode it is of course even better. I haven't had the patience 
to run the benches before the patch, i

Re: [PATCH] Help compiler detect invalid code

2019-09-25 Thread François Dumont
Some more tests have revealed  a small problem in is_sorted test. It was 
revealed by the Debug mode but not in a clean ways so for the moment I 
prefer to fix it and I'll add a _neg test when Debug is able to report 
it correctly.


I've also added a _neg test for equal which doesn't need Debug mode.

OK to commit ?

François



On 9/20/19 7:08 AM, François Dumont wrote:
I already realized that previous patch will be too controversial to be 
accepted.


In this new version I just implement a real memmove in __memmove so 
that in copy_backward there is no need for a shortcut to a more 
defensive code.


I'll see if in Debug mode I can do something.

François


On 9/19/19 10:27 PM, François Dumont wrote:

Hi

    I start working on making recently added constexpr tests to work 
in Debug mode.


    It appears that the compiler is able to detect code mistakes 
pretty well as long we don't try to hide the code intention with a 
defensive approach. This is why I'd like to propose to replace '__n > 
0' conditions with '__n != 0'.


    The result is demonstrated by the constexpr_neg.cc tests. What do 
you think ?


    * include/bits/stl_algobase.h (__memmove): Return _Tp*.
    (__memmove): Loop as long as __n is not 0.
    (__copy_move<>::__copy_m): Likewise.
    (__copy_move_backward<>::__copy_move_b): Likewise.
    * testsuite/25_algorithms/copy/constexpr.cc: Add check on copied 
values.

    * testsuite/25_algorithms/copy_backward/constexpr.cc: Likewise.
    * testsuite/25_algorithms/copy/constexpr_neg.cc: New.
    * testsuite/25_algorithms/copy_backward/constexpr.cc: New.

    I'll submit the patch to fix Debug mode depending on the decision 
for this one.


François





diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 4eba053ac75..94a79b85d15 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -83,27 +83,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*/
   template
 _GLIBCXX14_CONSTEXPR
-inline void*
-__memmove(_Tp* __dst, const _Tp* __src, size_t __num)
+inline void
+__memmove(_Tp* __dst, const _Tp* __src, ptrdiff_t __num)
 {
 #ifdef __cpp_lib_is_constant_evaluated
   if (std::is_constant_evaluated())
 	{
-	  for(; __num > 0; --__num)
+	  __dst += __num;
+	  __src += __num;
+	  for (; __num != 0; --__num)
 	{
 	  if constexpr (_IsMove)
-		*__dst = std::move(*__src);
+		*--__dst = std::move(*--__src);
 	  else
-		*__dst = *__src;
-	  ++__src;
-	  ++__dst;
+		*--__dst = *--__src;
 	}
-	  return __dst;
 	}
   else
 #endif
-	return __builtin_memmove(__dst, __src, sizeof(_Tp) * __num);
-  return __dst;
+	__builtin_memmove(__dst, __src, sizeof(_Tp) * __num);
 }
 
   /*
@@ -730,12 +728,6 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
 			 && __is_pointer<_BI2>::__value
 			 && __are_same<_ValueType1, _ValueType2>::__value);
 
-#ifdef __cpp_lib_is_constant_evaluated
-  if (std::is_constant_evaluated())
-	return std::__copy_move_backward::__copy_move_b(__first, __last,
-			   __result);
-#endif
   return std::__copy_move_backward<_IsMove, __simple,
    _Category>::__copy_move_b(__first,
  __last,
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/constexpr.cc b/libstdc++-v3/testsuite/25_algorithms/copy/constexpr.cc
index 67910b8773e..a0460603496 100644
--- a/libstdc++-v3/testsuite/25_algorithms/copy/constexpr.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/copy/constexpr.cc
@@ -24,12 +24,12 @@
 constexpr bool
 test()
 {
-  constexpr std::array ca0{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}};
+  constexpr std::array ca0{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}};
   std::array ma0{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
 
   const auto out6 = std::copy(ca0.begin(), ca0.begin() + 8, ma0.begin() + 2);
 
-  return out6 == ma0.begin() + 10;
+  return out6 == ma0.begin() + 10 && *(ma0.begin() + 2) == 1 && *out6 == 0;
 }
 
 static_assert(test());
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/constexpr_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy/constexpr_neg.cc
new file mode 100644
index 000..49052467409
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/copy/constexpr_neg.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2019 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 Gener

Re: Add std::copy_n overload for istreambuf_iterator

2019-10-10 Thread François Dumont
I think this build has been done between the 2 commits I used to apply 
this patch (because of a problem between the chair and the keyboard). 
Now it should be fine.


But it shows that it changed the behavior of std::copy_n as soon as the 
new specialization is being used.


Without this change the result is "12234" whereas with the 
specialization it is "12345". So in addition to being a nice perf 
enhancement this patch was also a partial fix for PR 81857.


Let me know Jonathan if there is something to do about it.

François

On 10/9/19 10:18 PM, Christophe Lyon wrote:



On Fri, 4 Oct 2019 at 07:01, François Dumont <mailto:frs.dum...@gmail.com>> wrote:


On 9/27/19 1:00 PM, Jonathan Wakely wrote:
    > On 19/07/19 23:37 +0200, François Dumont wrote:
>> It sounds reasonable to overload std::copy_n for
istreambuf_iterator.
> I wonder whether it's worth doing:
>
> #if __cplusplus >= 201703L
>    if constexpr (is_same_v<_OutputIterator, _CharT*>)
>  return __result + __it._M_sbuf->sgetn(__result, __n);
>    else
>  {
> #endif
>  ...
> #if __cplusplus >= 201703L
>  }
> #endif
>
> We could extend that to also work for basic_string<_CharT>::iterator
> and vector<_CharT>::iterator too if we wanted.
>
> I'm not sure if it will perform any better than the code below (it's
> approximately equivalent) but it should result in smaller
binaries, as we
> wouldn't be instantiating the code below when outputting to a
pointer
> or contiguous iterator.
>
> We don't need to do that now, it can be a separate patch later
(if we
> do it at all).

Very good remark, I hadn't check streambuf to find out if there were
better to do. For me it is the streambuf method to target for an
std::copy_n overload.

So here is a new proposal much simpler. I see no reason to enable it
only for char types, is there ?

Once the other patch on copy/copy_backward... algos is in I'll
provide
what necessary to benefit from the same optimization for std::deque
iterators and in Debug mode.

>
>> +#endif
>
> Because the matching #if is more than 40 lines away, please add a
> comment noting the condition that this corresponds to, i.e.
>
> #endif // C++11
Ok, done even if there is no 40 lines anymore. And also added it in
stl_algo.h.
>
>> +
>>   template
>>     typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
>> istreambuf_iterator<_CharT> >::__type
>> diff --git a/libstdc++-v3/include/std/streambuf
>> b/libstdc++-v3/include/std/streambuf
>> index d9ca981d704..4f62ebf4d95 100644
>> --- a/libstdc++-v3/include/std/streambuf
>> +++ b/libstdc++-v3/include/std/streambuf
>> @@ -155,6 +155,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> __copy_move_a2(istreambuf_iterator<_CharT2>,
>>    istreambuf_iterator<_CharT2>, _CharT2*);
>>
>> +#if __cplusplus >= 201103L
>> +  template> _OutputIterator>
>> +    friend typename enable_if<__is_char<_CharT2>::__value,
>> +  _OutputIterator>::type
>> +    copy_n(istreambuf_iterator<_CharT2>, _Size, _OutputIterator);
>> +#endif
>> +
>>   template
>>     friend typename
>> __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
>> istreambuf_iterator<_CharT2> >::__type
>> diff --git
>>
a/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator.cc
>>
b/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator.cc
>> new file mode 100644
>> index 000..ebd769cf7c0
>> --- /dev/null
>> +++
b/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator.cc
>> @@ -0,0 +1,59 @@
>> +// Copyright (C) 2019 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 L

[PATCH] Review std::copy istreambuf_iterator specialization

2019-10-08 Thread François Dumont

Hi

    Following what has been done for std::copy_n I think we could 
simplify the __copy_move_a2 overload to also use sgetn. Code is simpler 
and we avoid a friend declaration.


    Tested under Linux x86_64.


    * include/std/streambuf (__copy_move_a2): Remove friend declaration.
    * include/bits/streambuf_iterator.h (__copy_move_a2): Re-implement 
using

    streambuf in_avail and sgetn.

    Ok to commit ?

François

diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h b/libstdc++-v3/include/bits/streambuf_iterator.h
index e3e8736e768..134b3486b9a 100644
--- a/libstdc++-v3/include/bits/streambuf_iterator.h
+++ b/libstdc++-v3/include/bits/streambuf_iterator.h
@@ -345,31 +345,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		   istreambuf_iterator<_CharT> __last, _CharT* __result)
 {
   typedef istreambuf_iterator<_CharT>		   __is_iterator_type;
-  typedef typename __is_iterator_type::traits_type	   traits_type;
   typedef typename __is_iterator_type::streambuf_type  streambuf_type;
-  typedef typename traits_type::int_type		   int_type;
 
   if (__first._M_sbuf && !__last._M_sbuf)
 	{
 	  streambuf_type* __sb = __first._M_sbuf;
-	  int_type __c = __sb->sgetc();
-	  while (!traits_type::eq_int_type(__c, traits_type::eof()))
+	  std::streamsize __avail = __sb->in_avail();
+	  while (__avail > 0)
 	{
-	  const streamsize __n = __sb->egptr() - __sb->gptr();
-	  if (__n > 1)
-		{
-		  traits_type::copy(__result, __sb->gptr(), __n);
-		  __sb->__safe_gbump(__n);
-		  __result += __n;
-		  __c = __sb->underflow();
-		}
-	  else
-		{
-		  *__result++ = traits_type::to_char_type(__c);
-		  __c = __sb->snextc();
-		}
+	  __result += __sb->sgetn(__result, __avail);
+	  __avail = __sb->in_avail();
 	}
 	}
+
   return __result;
 }
 
diff --git a/libstdc++-v3/include/std/streambuf b/libstdc++-v3/include/std/streambuf
index d9ca981d704..3442f19bd78 100644
--- a/libstdc++-v3/include/std/streambuf
+++ b/libstdc++-v3/include/std/streambuf
@@ -149,12 +149,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   friend streamsize
   __copy_streambufs_eof<>(basic_streambuf*, basic_streambuf*, bool&);
 
-  template
-friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
-	   _CharT2*>::__type
-__copy_move_a2(istreambuf_iterator<_CharT2>,
-		   istreambuf_iterator<_CharT2>, _CharT2*);
-
   template
 friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
   istreambuf_iterator<_CharT2> >::__type


Re: copy/copy_backward/fill/fill_n/equal rework

2019-10-08 Thread François Dumont
Following recently committed patches some changes that couldn't be 
committed are now part of this patch.


Moreover testing istreambuf_iterator std::copy changes I realized that 
this specialization was broken because order of function declarations in 
stl_algobase.h was wrong. I'll check if I can find a way to confirm that 
a given overload is indeed being called.


So here is this patch again.

François

On 9/27/19 11:14 PM, François Dumont wrote:

On 9/27/19 2:28 PM, Jonathan Wakely wrote:

On 09/09/19 20:34 +0200, François Dumont wrote:

Hi

    This patch improves stl_algobase.h 
copy/copy_backward/fill/fill_n/equal implementations. The 
improvements are:


- activation of algo specialization for __gnu_debug::_Safe_iterator 
(w/o _GLIBCXX_DEBUG mode)


- activation of algo specialization for _Deque_iterator even if 
mixed with another kind of iterator.


- activation of algo specializations __copy_move_a2 for something 
else than pointers. For example this code:


std::vector v { 'a', 'b',  };

ostreambuf_iterator out(std::cout);

std::copy(v.begin(), v.end(), out);

is not calling the specialization __copy_move_a2(const char*, const 
char*, ostreambuf_iterator<>);


It also fix a _GLIBCXX_DEBUG issue where the __niter_base 
specialization was wrongly removing the _Safe_iterator<> layer. The 
testsuite/25_algorithms/copy/debug/1_neg.cc test case was failing on 
a debug assertion because _after_ the copy we were trying to 
increment the vector iterator after past-the-end. Of course the 
problem is the _after_, Debug mode should detect this _before_ it 
takes place which it does now.


Note that std::fill_n is now making use of std::fill for some 
optimizations dealing with random access iterators.


Performances are very good:


This looks good, but I'm unable to apply the patch:


error: patch failed: libstdc++-v3/include/bits/deque.tcc:967
error: libstdc++-v3/include/bits/deque.tcc: patch does not apply
error: patch failed: libstdc++-v3/include/bits/stl_algobase.h:499
error: libstdc++-v3/include/bits/stl_algobase.h: patch does not apply

Could you regenerate the patch (against a clean master tree) and
resend? Thanks.


Here it is, thanks.



diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc
index 3f77b4f079c..ab996ca52fa 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -967,155 +967,247 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   this->_M_impl._M_finish._M_set_node(__new_nstart + __old_num_nodes - 1);
 }
 
+_GLIBCXX_END_NAMESPACE_CONTAINER
+
   // Overload for deque::iterators, exploiting the "segmented-iterator
   // optimization".
-  template
+  template
 void
-fill(const _Deque_iterator<_Tp, _Tp&, _Tp*>& __first,
-	 const _Deque_iterator<_Tp, _Tp&, _Tp*>& __last, const _Tp& __value)
+__fill_a1(const _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*>& __first,
+	  const _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*>& __last,
+	  const _VTp& __value)
 {
-  typedef typename _Deque_iterator<_Tp, _Tp&, _Tp*>::_Self _Self;
+  typedef _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*> _Iter;
+  if (__first._M_node != __last._M_node)
+	{
+	  std::__fill_a1(__first._M_cur, __first._M_last, __value);
 
-  for (typename _Self::_Map_pointer __node = __first._M_node + 1;
-   __node < __last._M_node; ++__node)
-	std::fill(*__node, *__node + _Self::_S_buffer_size(), __value);
+	  for (typename _Iter::_Map_pointer __node = __first._M_node + 1;
+	   __node < __last._M_node; ++__node)
+	std::__fill_a1(*__node, *__node + _Iter::_S_buffer_size(), __value);
+
+	  std::__fill_a1(__last._M_first, __last._M_cur, __value);
+	}
+  else
+	std::__fill_a1(__first._M_cur, __last._M_cur, __value);
+}
 
+  template
+_OI
+__copy_move_dit(_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr> __first,
+		_GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr> __last,
+		_OI __result)
+{
+  typedef _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Ref, _Ptr> _Iter;
   if (__first._M_node != __last._M_node)
 	{
-	  std::fill(__first._M_cur, __first._M_last, __value);
-	  std::fill(__last._M_first, __last._M_cur, __value);
+	  __result
+	= std::__copy_move_a1<_IsMove>(__first._M_cur, __first._M_last,
+	   __result);
+
+	  for (typename _Iter::_Map_pointer __node = __first._M_node + 1;
+	   __node != __last._M_node; ++__node)
+	__result
+	  = std::__copy_move_a1<_IsMove>(*__node,
+	 *__node + _Iter::_S_buffer_size(),
+	 __result);
+
+	  return std::__copy_move_a1<_IsMove>(__last._M_first, __last._M_cur,
+	  __result);
 	}
-  else
-	std::fill(__first._M_cur, __last._M_cur, __value);
+
+  return std::__copy_move_a1<_IsMove>(__first._M_cur, __last._M_cur,
+	  __result);

Re: Add std::copy_n overload for istreambuf_iterator

2019-10-09 Thread François Dumont

On 10/9/19 10:18 PM, Christophe Lyon wrote:



On Fri, 4 Oct 2019 at 07:01, François Dumont <mailto:frs.dum...@gmail.com>> wrote:


On 9/27/19 1:00 PM, Jonathan Wakely wrote:
> On 19/07/19 23:37 +0200, François Dumont wrote:
>> It sounds reasonable to overload std::copy_n for
istreambuf_iterator.
> I wonder whether it's worth doing:
>
> #if __cplusplus >= 201703L
>    if constexpr (is_same_v<_OutputIterator, _CharT*>)
>  return __result + __it._M_sbuf->sgetn(__result, __n);
>    else
>  {
> #endif
>  ...
> #if __cplusplus >= 201703L
>  }
> #endif
>
> We could extend that to also work for basic_string<_CharT>::iterator
> and vector<_CharT>::iterator too if we wanted.
>
> I'm not sure if it will perform any better than the code below (it's
> approximately equivalent) but it should result in smaller
binaries, as we
> wouldn't be instantiating the code below when outputting to a
pointer
> or contiguous iterator.
>
> We don't need to do that now, it can be a separate patch later
(if we
> do it at all).

Very good remark, I hadn't check streambuf to find out if there were
better to do. For me it is the streambuf method to target for an
std::copy_n overload.

So here is a new proposal much simpler. I see no reason to enable it
only for char types, is there ?

Once the other patch on copy/copy_backward... algos is in I'll
provide
what necessary to benefit from the same optimization for std::deque
iterators and in Debug mode.

>
>> +#endif
>
> Because the matching #if is more than 40 lines away, please add a
> comment noting the condition that this corresponds to, i.e.
>
> #endif // C++11
Ok, done even if there is no 40 lines anymore. And also added it in
stl_algo.h.
>
>> +
>>   template
>>     typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
>> istreambuf_iterator<_CharT> >::__type
>> diff --git a/libstdc++-v3/include/std/streambuf
>> b/libstdc++-v3/include/std/streambuf
>> index d9ca981d704..4f62ebf4d95 100644
>> --- a/libstdc++-v3/include/std/streambuf
>> +++ b/libstdc++-v3/include/std/streambuf
>> @@ -155,6 +155,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> __copy_move_a2(istreambuf_iterator<_CharT2>,
>>    istreambuf_iterator<_CharT2>, _CharT2*);
>>
>> +#if __cplusplus >= 201103L
>> +  template> _OutputIterator>
>> +    friend typename enable_if<__is_char<_CharT2>::__value,
>> +  _OutputIterator>::type
>> +    copy_n(istreambuf_iterator<_CharT2>, _Size, _OutputIterator);
>> +#endif
>> +
>>   template
>>     friend typename
>> __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
>> istreambuf_iterator<_CharT2> >::__type
>> diff --git
>>
a/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator.cc
>>
b/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator.cc
>> new file mode 100644
>> index 000..ebd769cf7c0
>> --- /dev/null
>> +++
b/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator.cc
>> @@ -0,0 +1,59 @@
>> +// Copyright (C) 2019 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/>.
>> +
>> +// { dg-do run { target c++11 } }
>> +
>> +#include 
>> +#include 
>> +#include 
>> +
>> +#include 
>> +
>> +void test01()
>> +{
>> +  std::stringstream ss("12

[PATCH] Add std::__iterator_category_t

2019-10-03 Thread François Dumont

Hi

    May I add this convenient function ? I'll also use it in coming 
patches.


    Note that I removed a template parameter in __is_random_access_iter 
in C++11.



    * include/bits/stl_iterator_base_types.h (__iterator_category_t): 
Define

    for C++11.
    (__is_random_access_iter): Adapt to use latter.
    (_RequireInputIte): Likewise and use __enable_if_t.

    Tested under Linux x86_64.

François

diff --git a/libstdc++-v3/include/bits/stl_iterator_base_types.h b/libstdc++-v3/include/bits/stl_iterator_base_types.h
index 8135f4857fc..d12ac3a20ea 100644
--- a/libstdc++-v3/include/bits/stl_iterator_base_types.h
+++ b/libstdc++-v3/include/bits/stl_iterator_base_types.h
@@ -208,14 +208,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   //@}
 
 #if __cplusplus >= 201103L
+  template
+using __iterator_category_t
+  = typename iterator_traits<_Iter>::iterator_category;
+
   template
-using _RequireInputIter = typename
-  enable_if::iterator_category,
-			   input_iterator_tag>::value>::type;
+using _RequireInputIter =
+  __enable_if_t,
+   input_iterator_tag>::value>;
 
-  template,
-	   typename _Cat = typename _Traits::iterator_category>
+  template>
 struct __is_random_access_iter
   : is_base_of
 {


[PATCH] Add std::copy_n debug checks

2019-10-03 Thread François Dumont

Hi

    We are missing obvious debug checks in std::copy_n. Moreover I'll 
need them when I'll remove the Debug layer in a coming patch.


    Tested under Linux x86_64.


    * include/bits/stl_algo.h (copy_n): Add 
__glibcxx_requires_can_increment

    debug checks.
    * testsuite/25_algorithms/copy_n/debug/1_neg.cc: New.
    * testsuite/25_algorithms/copy_n/debug/2_neg.cc: New.

    I'll commit this day or this week end if not told otherwise.

François

diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h
index c1003077176..078efc028cc 100644
--- a/libstdc++-v3/include/bits/stl_algo.h
+++ b/libstdc++-v3/include/bits/stl_algo.h
@@ -816,6 +816,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
   __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator,
 	typename iterator_traits<_InputIterator>::value_type>)
+  __glibcxx_requires_can_increment(__first, __n);
+  __glibcxx_requires_can_increment(__result, __n);
 
   return std::__copy_n(__first, __n, __result,
 			   std::__iterator_category(__first));
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_n/debug/1_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy_n/debug/1_neg.cc
new file mode 100644
index 000..3e0e0299e1d
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/debug/1_neg.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2019 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
+// .
+
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include 
+#include 
+
+void
+test01()
+{
+  std::vector v1(3, 1);
+  std::vector v2(5, 0);
+
+  std::copy_n(v1.begin(), 5, v2.begin());
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_n/debug/2_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy_n/debug/2_neg.cc
new file mode 100644
index 000..ebc7cb5ea4c
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/debug/2_neg.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2019 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
+// .
+
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include 
+#include 
+
+void
+test01()
+{
+  std::vector v1(5, 1);
+  std::vector v2(3, 0);
+
+  std::copy_n(v1.begin(), 5, v2.begin());
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}


Re: [PATCH] Improve _Safe_iterator _M_distance_to

2019-10-04 Thread François Dumont

I eventually committed the attach patch.

The usage of __dp_sign_max_size will come later.

François

On 9/27/19 1:45 PM, Jonathan Wakely wrote:

On 16/09/19 22:31 +0200, François Dumont wrote:
    Here is the patch to improve _Safe_iterator<>::_M_get_distance_to 
implementation.


I introduced a new _Distance_precision  __sp_sign_max_size for 
occasions where we can't find out the exact size of a range but still 
get the max size of it. Thanks to this the performance tests are much 
better when dealing with list iterators:


Normal mode:

copy_backward_deque_iterators.cc    deque 2 list 5616r 5616u 
0s 0mem    0pf
copy_backward_deque_iterators.cc    list 2 deque 1586r 1586u 
0s 0mem    0pf
copy_deque_iterators.cc      deque 2 list     5495r 
5495u    0s 0mem    0pf
copy_deque_iterators.cc      list 2 deque     2400r 
2400u    0s 0mem    0pf


Debug mode:

copy_backward_deque_iterators.cc    deque 2 list 5789r 5785u 
1s 0mem    0pf
copy_backward_deque_iterators.cc    list 2 deque 1656r 1655u 
0s 0mem    0pf
copy_deque_iterators.cc      deque 2 list     5792r 
5793u    0s 0mem    0pf
copy_deque_iterators.cc      list 2 deque     2636r 
2636u    0s 0mem    0pf


Tested under Linux x86_64.

I'll commit once other patches are in.


    * include/debug/forward_list
(_Sequence_traits<__debug::forward_list<>>::_S_size): Returns __dp_sign
    distance when not empty.
    * include/debug/list
    (_Sequence_traits<__debug::list<>>::_S_size): Likewise.
    * include/debug/helper_functions.h (__dp_sign_max_size): New
    _Distance_precision enum entry.
    * include/debug/safe_iterator.h
    (__copy_move_a(_II, _II, const _Safe_iterator<>&)): Check for output
    iterator _M_can_advance as soon as input range distance precision is
    strictly higher than __dp_size.
    (__copy_move_a(const _Safe_iterator<>&, const _Safe_iterator<>&,
    const _Safe_iterator<>&)): Likewise.
    (__copy_move_backward_a(_II, _II, const _Safe_iterator<>&)): 
Likewise.

    (__copy_move_backward_a(const _Safe_iterator<>&,
    const _Safe_iterator<>&, const _Safe_iterator<>&)): Likewise.
    (__equal_aux(_II, _II, const _Safe_iterator<>&)): Likewise.
    (__equal_aux(const _Safe_iterator<>&,
    const _Safe_iterator<>&, const _Safe_iterator<>&)): Likewise.


The patch looks OK, but the safe_iterator.tcc changes are not listed
in the changelog, and those are the most complex part of the patch.

Please add a changelog entry for the _M_get_distance_to changes. OK
for trunk after that, thanks.





diff --git a/libstdc++-v3/include/debug/forward_list b/libstdc++-v3/include/debug/forward_list
index e30b09e..f1756ddec9d 100644
--- a/libstdc++-v3/include/debug/forward_list
+++ b/libstdc++-v3/include/debug/forward_list
@@ -911,7 +911,7 @@ namespace __gnu_debug
   _S_size(const std::__debug::forward_list<_Tp, _Alloc>& __seq)
   {
 	return __seq.empty()
-	  ? std::make_pair(0, __dp_exact) : std::make_pair(1, __dp_equality);
+	  ? std::make_pair(0, __dp_exact) : std::make_pair(1, __dp_sign);
   }
 };
 
diff --git a/libstdc++-v3/include/debug/helper_functions.h b/libstdc++-v3/include/debug/helper_functions.h
index 475fdda1d7b..5a920bb9a6f 100644
--- a/libstdc++-v3/include/debug/helper_functions.h
+++ b/libstdc++-v3/include/debug/helper_functions.h
@@ -50,10 +50,11 @@ namespace __gnu_debug
*/
   enum _Distance_precision
 {
-  __dp_none,	// Not even an iterator type
-  __dp_equality,	//< Can compare iterator equality, only
-  __dp_sign,	//< Can determine equality and ordering
-  __dp_exact	//< Can determine distance precisely
+  __dp_none,		// Not even an iterator type
+  __dp_equality,		//< Can compare iterator equality, only
+  __dp_sign,		//< Can determine equality and ordering
+  __dp_sign_max_size,	//< __dp_sign and gives max range size
+  __dp_exact		//< Can determine distance precisely
 };
 
   template= 0;
 	}
diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list
index 5eb9a6094e3..140546a633e 100644
--- a/libstdc++-v3/include/debug/list
+++ b/libstdc++-v3/include/debug/list
@@ -916,7 +916,7 @@ namespace __gnu_debug
   _S_size(const std::__debug::list<_Tp, _Alloc>& __seq)
   {
 	return __seq.empty()
-	  ? std::make_pair(0, __dp_exact) : std::make_pair(1, __dp_equality);
+	  ? std::make_pair(0, __dp_exact) : std::make_pair(1, __dp_sign);
   }
 };
 #endif
diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc b/libstdc++-v3/include/debug/safe_iterator.tcc
index 581c51c9607..1750bc473d2 100644
--- a/libstdc++-v3/include/debug/safe_iterator.tcc
+++ b/libstdc++-v3/include/debug/safe_iterator.tcc
@@ -113,18 +113,22 @@ namespace __gnu_d

[PATCH] Implement std::advance for istreambuf_iterator using pubseekoff

2019-10-14 Thread François Dumont
The same way I proposed to review std::copy overload for 
istreambuf_iterator we can implement std::advance using pubseekoff.


It is both a cleaner implementation and avoids yet another friend 
declaration.



    * include/std/streambuf
    (advance(istreambuf_iterator<>&, _Distance)): Remove friend 
declaration.
    * include/bits/streambuf_iterator.h (__copy_move_a2): Re-implement 
using

    streambuf pubseekoff.

Tested under Linux x86_64.

Ok to commit ?

François

diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h b/libstdc++-v3/include/bits/streambuf_iterator.h
index 134b3486b9a..afe5c95f021 100644
--- a/libstdc++-v3/include/bits/streambuf_iterator.h
+++ b/libstdc++-v3/include/bits/streambuf_iterator.h
@@ -434,34 +434,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			  _M_message(__gnu_debug::__msg_inc_istreambuf)
 			  ._M_iterator(__i));
 
-  typedef istreambuf_iterator<_CharT>		   __is_iterator_type;
-  typedef typename __is_iterator_type::traits_type	   traits_type;
-  typedef typename __is_iterator_type::streambuf_type  streambuf_type;
-  typedef typename traits_type::int_type		   int_type;
-  const int_type __eof = traits_type::eof();
-
-  streambuf_type* __sb = __i._M_sbuf;
-  while (__n > 0)
-	{
-	  streamsize __size = __sb->egptr() - __sb->gptr();
-	  if (__size > __n)
-	{
-	  __sb->__safe_gbump(__n);
-	  break;
-	}
-
-	  __sb->__safe_gbump(__size);
-	  __n -= __size;
-	  if (traits_type::eq_int_type(__sb->underflow(), __eof))
-	{
-	  __glibcxx_requires_cond(__n == 0,
-_M_message(__gnu_debug::__msg_inc_istreambuf)
-._M_iterator(__i));
-	  break;
-	}
-	}
+#ifdef _GLIBCXX_DEBUG
+  typedef basic_streambuf<_CharT> __streambuf_t;
+  typedef typename __streambuf_t::pos_type __pos_type;
+  __pos_type __cur_pos
+	= __i._M_sbuf->pubseekoff(0, ios_base::cur, ios_base::in);
+  __pos_type __new_pos =
+#endif
+  __i._M_sbuf->pubseekoff(__n, ios_base::cur, ios_base::in);
+  __i._M_c = char_traits<_CharT>::eof();
 
-  __i._M_c = __eof;
+  __glibcxx_requires_cond(__new_pos - __cur_pos == __n,
+			  _M_message(__gnu_debug::__msg_inc_istreambuf)
+			  ._M_iterator(__i));
 }
 
 // @} group iterators
diff --git a/libstdc++-v3/include/std/streambuf b/libstdc++-v3/include/std/streambuf
index 3442f19bd78..ef03da39bc2 100644
--- a/libstdc++-v3/include/std/streambuf
+++ b/libstdc++-v3/include/std/streambuf
@@ -155,11 +155,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 find(istreambuf_iterator<_CharT2>, istreambuf_iterator<_CharT2>,
 	 const _CharT2&);
 
-  template
-friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
-	   void>::__type
-advance(istreambuf_iterator<_CharT2>&, _Distance);
-
   template
 friend basic_istream<_CharT2, _Traits2>&
 operator>>(basic_istream<_CharT2, _Traits2>&, _CharT2*);


Re: [PATCH][Hashtable 0/6] Code review

2019-12-19 Thread François Dumont
After further work on pretty printers I prefer to stay closer to what is 
done currently. It works better with another patch I'll submit one day.


The drawback is that I needed to consider versioned namespace in 
template parameters passed to lookup_templ_spec.


François


On 12/9/19 10:15 PM, François Dumont wrote:

This patch also require an update of the printers.py file.

Here is an updated version.

François

On 11/17/19 9:42 PM, François Dumont wrote:

This is the begining of a patch series for _Hashtable

Initial patch to clarify code. I was tired to see true/false or 
true_type/false_type without knowing what was true/false.


I also made code more consistent by chosing to specialize methods 
through usage of __unique_keys_t/__multi_keys_t rather than calling 
them _M_[multi]_XXX.



    * include/bits/hashtable_policy.h (__detail::__unique_keys_t): New.
    (__detail::__multi_keys_t): New.
    (__detail::__constant_iterators_t): New.
    (__detail::__mutable_iterators_t): New.
    (__detail::__hash_cached_t): New.
    (__detail::__hash_not_cached_t): New.
    (_Hash_node<>): Change _Cache_hash_code template parameter from 
bool to

    typename. Adapt partial specializations.
    (_Node_iterator_base<>): Likewise.
    (operator==(const _Node_iterator_base<>&,const 
_Node_iterator_base<>&)):

    Adapt.
    (operator!=(const _Node_iterator_base<>&,const 
_Node_iterator_base<>&)):

    Adapt.
    (_Node_iterator<>): Change __constant_iterators and __cache template
    parameters from bool to typename.
    (_Node_const_iterator<>): Likewise.
    (_Map_base<>): Change _Unique_keys template parameter from bool to
    typename. Adapt partial specializations.
    (_Insert<>): Change _Constant_iterators template parameter from 
bool to

    typename. Adapt partial specializations.
    (_Local_iterator_base<>): Change __cache_hash_code template 
parameter

    from bool to typename. Adapt partial specialization.
    (_Hash_code_base<>): Likewise.
    (operator==(const _Local_iterator_base<>&,
    const _Local_iterator_base<>&)): Adapt.
    (operator!=(const _Local_iterator_base<>&,
    const _Local_iterator_base<>&)):
    Adapt.
    (_Local_iterator<>): Change __constant_iterators and __cache 
template

    parameters from bool to typename.
    (_Local_const_iterator<>): Likewise.
    (_Hashtable_base<>): Adapt.
    (_Equal_hash_code<>): Adapt.
    (_Equality<>): Adapt.
    * include/bits/hashtable.h (_Hashtable<>): Replace occurences of
    true_type/false_type by respoectively 
__unique_type_t/__multi_type_t.

    (_M_insert_unique_node(const key_type&, size_t, __hash_code,
    __node_type*, size_t)): Replace by...
    (_M_insert_node(__unique_keys_t, size_t, __hash_code, __node_type*,
    size_t)): ...this.
    (_M_insert_muti_node(__node_type*, const key_type&, __hash_code,
    __node_type*)): Replace by...
    (_M_insert_node(__multi_keys_t, __node_type*, __hash_code,
    __node_type*)): ...this.
    (_M_reinsert_node(node_type&&)): Replace by...
    (_M_reinsert_node(node_type&&, __unique_keys_t)): ...this.
    (_M_reinsert_node(const_iterator, node_type&&, __unique_keys_t)): 
New,

    forward to latter.
    (_M_reinsert_node_multi(const_iterator, node_type&&)): Replace by...
    (_M_reinsert_node(const_iterator, node_type&&, __multi_keys_t)):
    ...this.
    (_M_reinsert_node(node_type&&, __multi_keys_t)): New, forward to 
latter.

    (_M_reinsert_node(node_type&&)): New, use latters.
    (_M_reinsert_node(const_iterator, node_type&&)): Likewise.
    (_M_merge_unique(_Compatible_Hashtable&)): Replace by...
    (_M_merge(__unique_keys_t, _Compatible_Hashtable&)): ...this.
    (_M_merge_multi(_Compatible_Hashtable&)): Replace by...
    (_M_merge(__multi_keys_t, _Compatible_Hashtable&)): ...this.
    (_M_merge(_Compatible_Hashtable&)): New, use latters.
    * include/bits/unordered_map.h
    (unordered_map<>::insert(const_iterator, node_type&&)): Adapt.
    (unordered_map<>::merge(unordered_map<>&)): Adapt.
(unordered_map<>::merge(unordered_multimap<>&)): Adapt.
    (unordered_multimap<>::insert(node_type&&)): Adapt.
    (unordered_multimap<>::insert(const_iterator, node_type&&)): Adapt.
(unordered_multimap<>::merge(unordered_multimap<>&)): Adapt.
(unordered_multimap<>::merge(unordered_map<>&)): Adapt.
    * include/bits/unordered_set.h
    (unordered_set<>::insert(const_iterator, node_type&&)): Adapt.
    (unordered_set<>::merge(unordered_set<>&)): Adapt.
(unordered_set<>::merge(unordered_multiset<>&)): Adapt.
    (unordered_multiset<>::insert(node_type&&)): Adapt.
    (unordered

Re: [PATCH][Hashtable 5/6] Remove H1/H2 template parameters

2019-12-19 Thread François Dumont

Because of this change printers.py has to be updated too.

François


On 11/17/19 10:15 PM, François Dumont wrote:
H1 used to be a reference to the user Hash, now _Hashtable and 
unordered types agree on the same Hash type which is more intuitive.


I also chose to not support anymore a stateful ranged hash functor. We 
only use _Mod_range_hashing and _Mask_range_hashing.


Thanks to this simplification _M_bucket_index can also be simplified.

    * include/bits/hashtable_policy.h (_Hashtable<>): Remove _H1 and _H2
    template parameters.
    (_Hastable_base<>): Likewise.
    (_Default_ranged_hash): Remove.
    (_Prime_rehash_policy::__ranged_hash): New.
    (_Power2_rehash_policy::__ranged_hash): New.
    (_Map_base<>): Remove _H1 and _H2 template parameters.
    (_Insert_base<>): Likewise.
    (_Insert<>): Likewise.
    (_Rehash_base<>): Likewise.
    (_Local_iterator_base<>): Remove _H1 and _H2 template parameters 
and add

    _RangedHash.
    (_Hash_code_base<>): Likewise.
    (_Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash,
    __hash_not_cached_t>): Remove.
    (_Hash_code_base<>::_M_bucket_index(const _Key&, __hash_code, 
size_t)):

    Replace by...
    (_Hash_code_base<>::_M_bucket_index(__hash_code, size_t)): ...this.
    (_Local_iterator<>): Remove _H1 and _H2 template parameters.
    (_Local_const_iterator<>): Likewise.
    (_Equality<>): Likewise.
    * include/bits/hashtable.h (_Hashtable<>): Remove _H1 and _H2 
template

    parameters.
    * include/bits/node_handle.h: Adapt.
    * include/bits/unordered_map.h: Adapt.
    * include/bits/unordered_set.h: Adapt.
    * testsuite/23_containers/unordered_set/hash_policy/26132.cc: Adapt.
    * testsuite/23_containers/unordered_set/hash_policy/71181.cc: Adapt.
    * testsuite/23_containers/unordered_set/hash_policy/load_factor.cc:
    Adapt.
    * testsuite/23_containers/unordered_set/hash_policy/rehash.cc: Adapt.
    * testsuite/23_containers/unordered_set/insert/hash_policy.cc: Adapt.
    * 
testsuite/23_containers/unordered_set/max_load_factor/robustness.cc:

    Adapt.
    * testsuite/performance/23_containers/insert/54075.cc: Adapt.
    * testsuite/performance/23_containers/insert_erase/41975.cc: Adapt.
    * testsuite/performance/23_containers/insert_erase/
    unordered_small_size.cc: Adapt.

Tested under Linux x86_64.

François




diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 41be821782d..9dadc62e328 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -69,31 +69,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*  and returns a bool-like value that is true if the two objects
*  are considered equal.
*
-   *  @tparam _H1  The hash function. A unary function object with
+   *  @tparam _Hash  The hash function. A unary function object with
*  argument type _Key and result type size_t. Return values should
*  be distributed over the entire range [0, numeric_limits:::max()].
*
-   *  @tparam _H2  The range-hashing function (in the terminology of
-   *  Tavori and Dreizin).  A binary function object whose argument
-   *  types and result type are all size_t.  Given arguments r and N,
-   *  the return value is in the range [0, N).
-   *
-   *  @tparam _Hash  The ranged hash function (Tavori and Dreizin). A
-   *  binary function whose argument types are _Key and size_t and
-   *  whose result type is size_t.  Given arguments k and N, the
-   *  return value is in the range [0, N).  Default: hash(k, N) =
-   *  h2(h1(k), N).  If _Hash is anything other than the default, _H1
-   *  and _H2 are ignored.
-   *
-   *  @tparam _RehashPolicy  Policy class with three members, all of
-   *  which govern the bucket count. _M_next_bkt(n) returns a bucket
-   *  count no smaller than n.  _M_bkt_for_elements(n) returns a
-   *  bucket count appropriate for an element count of n.
-   *  _M_need_rehash(n_bkt, n_elt, n_ins) determines whether, if the
-   *  current bucket count is n_bkt and the current element count is
-   *  n_elt, we need to increase the bucket count.  If so, returns
-   *  make_pair(true, n), where n is the new bucket count.  If not,
-   *  returns make_pair(false, )
+   *  @tparam _RehashPolicy  Policy class with three members, all of which
+   *  govern the bucket count. _M_next_bkt(n) returns a bucket count no smaller
+   *  than n. _M_bkt_for_elements(n) returns a bucket count appropriate for an
+   *  element count of n. _M_need_rehash(n_bkt, n_elt, n_ins) determines
+   *  whether, if the current bucket count is n_bkt and the current element
+   *  count is n_elt, we need to increase the bucket count for n_ins insertions.
+   *  If so, returns make_pair(true, n), where n is the new bucket count. If
+   *  not, returns make_pair(false, )
*
*  @tparam _Traits  Compile-time class with three boolean
*

[PATCH] Fix versioned namespace test failures

2019-12-20 Thread François Dumont

Comitted as trivial.

After this I only have 1 failure left specific to versioned namespace in 
pretty printers tests.


    * testsuite/23_containers/map/48101_neg.cc: Add versioned namespace
    pattern to tested error message.
    * testsuite/23_containers/multimap/48101_neg.cc: Likewise.
    * testsuite/30_threads/headers/stop_token/synopsis.cc: Add
    dg-require-normal-namepace.

François

diff --git a/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc
index 8a7429c85a8..ed80ba6 100644
--- a/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc
@@ -29,8 +29,8 @@ test01()
   c2.find(2); // { dg-error "here" }
 }
 
-// { dg-error "_Compare = std::less" "" { target *-*-* } 0 }
-// { dg-error "_Compare = std::allocator" "" { target *-*-* } 0 }
+// { dg-error "_Compare = std::(__8::)?less" "" { target *-*-* } 0 }
+// { dg-error "_Compare = std::(__8::)?allocator" "" { target *-*-* } 0 }
 // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 }
 // { dg-prune-output "no match for call" }
 // { dg-prune-output "invalid conversion" }
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc
index 7bd56cc9c73..513822cc96f 100644
--- a/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc
@@ -29,8 +29,8 @@ test01()
   c2.find(2); // { dg-error "here" }
 }
 
-// { dg-error "_Compare = std::less" "" { target *-*-* } 0 }
-// { dg-error "_Compare = std::allocator" "" { target *-*-* } 0 }
+// { dg-error "_Compare = std::(__8::)?less" "" { target *-*-* } 0 }
+// { dg-error "_Compare = std::(__8::)?allocator" "" { target *-*-* } 0 }
 // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 }
 // { dg-prune-output "no match for call" }
 // { dg-prune-output "invalid conversion" }
diff --git a/libstdc++-v3/testsuite/30_threads/headers/stop_token/synopsis.cc b/libstdc++-v3/testsuite/30_threads/headers/stop_token/synopsis.cc
index b185bc7be39..59b3e772d99 100644
--- a/libstdc++-v3/testsuite/30_threads/headers/stop_token/synopsis.cc
+++ b/libstdc++-v3/testsuite/30_threads/headers/stop_token/synopsis.cc
@@ -17,6 +17,7 @@
 
 // { dg-options "-std=gnu++2a" }
 // { dg-do compile { target c++2a } }
+// { dg-require-normal-namespace "" }
 
 #include 
 


[PATCH] PR libstdc++/91620 Implement DR 526 for std::[forward_]list::remove_if/unique

2019-12-27 Thread François Dumont
Here is the patch to extend DR 526 to forward_list and list remove_if 
and unique.


As the adopted pattern is simpler I also applied it to the remove methods.

    PR libstdc++/91620
    * include/bits/forward_list.tcc (forward_list<>::remove): Collect nodes
    to destroy in an intermediate forward_list.
    (forward_list<>::remove_if, forward_list<>::unique): Likewise.
    * include/bits/list.tcc (list<>::remove, list<>::unique): Likewise.
    (list<>::remove_if): Likewise.
    * include/debug/forward_list (forward_list<>::_M_erase_after): Remove.
    (forward_list<>::erase_after): Adapt.
    (forward_list<>::remove, forward_list<>::remove_if): Collect nodes to
    destroy in an intermediate forward_list.
    (forward_list<>::unique): Likewise.
    * include/debug/list (list<>::remove, list<>::unique): Likewise.
    (list<>::remove_if): Likewise.

Tested under Linux x86_64 normal and debug modes.

Ok to commit ?

François

diff --git a/libstdc++-v3/include/bits/forward_list.tcc b/libstdc++-v3/include/bits/forward_list.tcc
index 088111e3330..70de7e75a43 100644
--- a/libstdc++-v3/include/bits/forward_list.tcc
+++ b/libstdc++-v3/include/bits/forward_list.tcc
@@ -290,30 +290,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 remove(const _Tp& __val) -> __remove_return_type
 {
   size_type __removed __attribute__((__unused__)) = 0;
-  _Node_base* __curr = >_M_impl._M_head;
-  _Node_base* __extra = nullptr;
+  forward_list __to_destroy(get_allocator());
 
-  while (_Node* __tmp = static_cast<_Node*>(__curr->_M_next))
-	{
+  auto __prev_it = cbefore_begin();
+  while (_Node* __tmp = static_cast<_Node*>(__prev_it._M_node->_M_next))
 	if (*__tmp->_M_valptr() == __val)
 	  {
-	  if (__tmp->_M_valptr() != std::__addressof(__val))
-		{
-		  this->_M_erase_after(__curr);
+	__to_destroy.splice_after(__to_destroy.cbefore_begin(),
+  *this, __prev_it);
 	_GLIBCXX20_ONLY( __removed++ );
-		  continue;
 	  }
 	else
-		__extra = __curr;
-	}
-	  __curr = __curr->_M_next;
-	}
+	  ++__prev_it;
 
-  if (__extra)
-	{
-	  this->_M_erase_after(__extra);
-	  _GLIBCXX20_ONLY( __removed++ );
-	}
   return _GLIBCXX20_ONLY( __removed );
 }
 
@@ -324,17 +313,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   remove_if(_Pred __pred) -> __remove_return_type
   {
 	size_type __removed __attribute__((__unused__)) = 0;
-	_Node_base* __curr = >_M_impl._M_head;
-	while (_Node* __tmp = static_cast<_Node*>(__curr->_M_next))
-	  {
+	forward_list __to_destroy(get_allocator());
+
+	auto __prev_it = cbefore_begin();
+	while (_Node* __tmp = static_cast<_Node*>(__prev_it._M_node->_M_next))
 	  if (__pred(*__tmp->_M_valptr()))
 	{
-		this->_M_erase_after(__curr);
+	  __to_destroy.splice_after(__to_destroy.cbefore_begin(),
+	*this, __prev_it);
 	  _GLIBCXX20_ONLY( __removed++ );
 	}
 	  else
-	  __curr = __curr->_M_next;
-	  }
+	++__prev_it;
+
 	return _GLIBCXX20_ONLY( __removed );
   }
 
@@ -348,19 +339,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	iterator __last = end();
 	if (__first == __last)
 	  return _GLIBCXX20_ONLY(0);
+
+	forward_list __to_destroy(get_allocator());
 	size_type __removed __attribute__((__unused__)) = 0;
 	iterator __next = __first;
 	while (++__next != __last)
 	{
 	  if (__binary_pred(*__first, *__next))
 	{
-	  erase_after(__first);
+	  __to_destroy.splice_after(__to_destroy.cbefore_begin(),
+	*this, __first);
 	  _GLIBCXX20_ONLY( __removed++ );
 	}
 	  else
 	__first = __next;
 	  __next = __first;
 	}
+
 	return _GLIBCXX20_ONLY( __removed );
   }
 
diff --git a/libstdc++-v3/include/bits/list.tcc b/libstdc++-v3/include/bits/list.tcc
index 0ac6654b079..5a6fd5b0824 100644
--- a/libstdc++-v3/include/bits/list.tcc
+++ b/libstdc++-v3/include/bits/list.tcc
@@ -331,10 +331,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 list<_Tp, _Alloc>::
 remove(const value_type& __value)
 {
+#if !_GLIBCXX_USE_CXX11_ABI
   size_type __removed __attribute__((__unused__)) = 0;
+#endif
+  list __to_destroy(get_allocator());
   iterator __first = begin();
   iterator __last = end();
-  iterator __extra = __last;
   while (__first != __last)
 	{
 	  iterator __next = __first;
@@ -344,22 +346,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
 	  // 526. Is it undefined if a function in the standard changes
 	  // in parameters?
-	  if (std::__addressof(*__first) != std::__addressof(__value))
-		{
-		  _M_erase(__first);
+	  __to_destroy.splice(__to_destroy.begin(), *this, __first);
+#if !_GLIBCXX_USE_CXX11_ABI
 	  _GLIBCXX20_ONLY( __removed++ );
+#endif
 	}
-	  else
-		__extra = __first;
-	}
+
 	  __first = __next;
 	}
-  if (__extra != __last)
-	{
-	  _M_erase(__extra);
-	  _GLIBCXX20_ONLY( __removed++ );
-	}
+
+#if !_GLIBCXX_USE_CXX11_ABI
 	return _GLIBCXX20_ONLY( __removed );
+#else
+	return _GLIBCXX20_ONLY( __to_destroy.size() 

[PATCH] Make __glibcxx_assert constexpr compatible

2020-02-10 Thread François Dumont
By making __glibcxx_assert constexpr compatible we can get rid of a 
FIXME in basic_string_view and so fix following XPASS in _GLIBCXX_DEBUG 
modes.


XPASS: 21_strings/basic_string_view/element_access/char/2.cc execution test
XPASS: 21_strings/basic_string_view/element_access/wchar_t/2.cc 
execution test


Should I also rename those in 2_neg.cc ?

I had to move the assert block in c++config to benefit from 
_GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED definition. The generation 
of the compilation error is not very nice but it is still better than no 
error and we can see the assertion:


/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/21_strings/basic_string_view/element_access/wchar_t/constexpr_neg.cc:31:22: 
erreur: condition non constante pour l'assertion statique
   31 | static_assert(test() == 0); // { dg-error "non-constant 
condition" }

  |   ~~~^~~~
Dans le fichier inclus depuis 
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/limits:42,
 depuis 
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/string_view:40,
 depuis 
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/21_strings/basic_string_view/element_access/wchar_t/constexpr_neg.cc:21:
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/21_strings/basic_string_view/element_access/wchar_t/constexpr_neg.cc:31:19: 
dans l'expansion « constexpr » de « test() »
/home/fdt/dev/gcc/git/libstdc++-v3/testsuite/21_strings/basic_string_view/element_access/wchar_t/constexpr_neg.cc:28:13: 
dans l'expansion « constexpr » de 
« s.std::basic_string_view::operator[](4) »
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/string_view:206:2: 
erreur: inline assembly is not a constant expression

  206 |  __glibcxx_assert(__pos < this->_M_len);
  |  ^~~~
/home/fdt/dev/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/string_view:206:2: 
note: only unevaluated inline assembly is allowed in a « constexpr » 
function in C++2a


    * include/bits/c++config
[_GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED](__glibcxx_assert_impl):
    New.
    * include/std/string_view 
(basic_string_view<>:operator[](size_type)):

    Restore __glibcxx_assert.
    (basic_string_view<>::front()): Likewise.
    (basic_string_view<>::back()): Likewise.
    * 
testsuite/21_strings/basic_string_view/element_access/char/back_constexpr_neg.cc:

    New.
    * 
testsuite/21_strings/basic_string_view/element_access/char/constexpr.cc:

    New.
    * 
testsuite/21_strings/basic_string_view/element_access/char/constexpr_neg.cc:

    New.
    * 
testsuite/21_strings/basic_string_view/element_access/char/front_back_constexpr.cc:

    New.
    * 
testsuite/21_strings/basic_string_view/element_access/char/front_constexpr_neg.cc:

    New.
    * 
testsuite/21_strings/basic_string_view/element_access/wchar_t/constexpr.cc:

    New.
    * 
testsuite/21_strings/basic_string_view/element_access/wchar_t/constexpr_neg.cc:

    New.

Tested under Linux x86_64 normal and debug modes.

Ok to commit ?

François

diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index b1fad59d4b3..4d821627447 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -441,37 +441,6 @@ namespace std
 # define _GLIBCXX_EXTERN_TEMPLATE -1
 #endif
 
-// Assert.
-#if defined(_GLIBCXX_ASSERTIONS) \
-  || defined(_GLIBCXX_PARALLEL) || defined(_GLIBCXX_PARALLEL_ASSERTIONS)
-namespace std
-{
-  // Avoid the use of assert, because we're trying to keep the 
-  // include out of the mix.
-  extern "C++" inline void
-  __replacement_assert(const char* __file, int __line,
-		   const char* __function, const char* __condition)
-  {
-__builtin_printf("%s:%d: %s: Assertion '%s' failed.\n", __file, __line,
-		 __function, __condition);
-__builtin_abort();
-  }
-}
-#define __glibcxx_assert_impl(_Condition) \
-  do 	 \
-  {			  		 \
-if (! (_Condition))  \
-  std::__replacement_assert(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
-#_Condition); \
-  } while (false)
-#endif
-
-#if defined(_GLIBCXX_ASSERTIONS)
-# define __glibcxx_assert(_Condition) __glibcxx_assert_impl(_Condition)
-#else
-# define __glibcxx_assert(_Condition)
-#endif
-
 // Macros for race detectors.
 // _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(A) and
 // _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(A) should be used to explain
@@ -663,6 +632,53 @@ namespace std
 # endif
 #endif // GCC
 
+// Assert.
+#if defined(_GLIBCXX_ASSERTIONS) \
+  || defined(_GLIBCXX_PARALLEL) || defined(_GLIBCXX_PARALLEL_ASSERTIONS)
+namespace std
+{
+  // Avoid the use of assert, because we're trying to keep the 
+  // include out of the mix.
+  extern "C++" inline void
+  

Fix Debug mode Undefined Behavior

2020-03-03 Thread François Dumont
After the fix of PR 91910 I tried to consider other possible race 
condition and I think we still have a problem.


Like stated in the PR when a container is destroyed all associated 
iterators are made singular. If at the same time another thread try to 
access this iterator the _M_singular check will face a data race when 
accessing _M_sequence member. In case of race condition the program is 
likely to abort but maybe because of memory access violation rather than 
a clear singular iterator assertion.


To avoid this I rework _M_sequence manipulation to use atomic read when 
necessary and make sure that otherwise container mutex is locked.


    * src/c++/debug.cc
    (_Safe_sequence_base::_M_attach_single): Set attached iterator
    sequence pointer and version.
    (_Safe_sequence_base::_M_detach_single): Reset detached 
iterator.
    (_Safe_iterator_base::_M_attach): Remove attached iterator 
sequence

    pointer and version assignments.
    (_Safe_iterator_base::_M_attach_single): Likewise.
    (_Safe_iterator_base::_M_detach_single): Remove detached 
iterator

    reset.
    (_Safe_iterator_base::_M_singular): Use atomic load to 
access parent

    sequence.
    (_Safe_iterator_base::_M_can_compare): Likewise.
    (_Safe_iterator_base::_M_get_mutex): Likewise.
    (_Safe_local_iterator_base::_M_attach): Remove attached 
iterator container

    pointer and version assignments.
    (_Safe_local_iterator_base::_M_attach_single): Likewise.
(_Safe_unordered_container_base::_M_attach_local_single):
    Set attached iterator container pointer and version.
(_Safe_unordered_container_base::_M_detach_local_single): Reset detached
    iterator.

Running tests in Debug mode.

Ok to commit if successful ?

François

diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc
index 18da9da9c52..711ba558eb2 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -318,6 +318,8 @@ namespace __gnu_debug
   _Safe_sequence_base::
   _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw ()
   {
+__it->_M_sequence = this;
+__it->_M_version = _M_version;
 _Safe_iterator_base*& __its =
   __constant ? _M_const_iterators : _M_iterators;
 __it->_M_next = __its;
@@ -341,6 +343,7 @@ namespace __gnu_debug
   {
 // Remove __it from this sequence's list
 __it->_M_unlink();
+__it->_M_reset();
 if (_M_const_iterators == __it)
   _M_const_iterators = __it->_M_next;
 if (_M_iterators == __it)
@@ -355,11 +358,7 @@ namespace __gnu_debug
 
 // Attach to the new sequence (if there is one)
 if (__seq)
-  {
-	_M_sequence = __seq;
-	_M_version = _M_sequence->_M_version;
-	_M_sequence->_M_attach(this, __constant);
-  }
+  __seq->_M_attach(this, __constant);
   }
 
   void
@@ -370,11 +369,7 @@ namespace __gnu_debug
 
 // Attach to the new sequence (if there is one)
 if (__seq)
-  {
-	_M_sequence = __seq;
-	_M_version = _M_sequence->_M_version;
-	_M_sequence->_M_attach_single(this, __constant);
-  }
+  __seq->_M_attach_single(this, __constant);
   }
 
   void
@@ -400,10 +395,7 @@ namespace __gnu_debug
   _M_detach_single() throw ()
   {
 if (_M_sequence)
-  {
-	_M_sequence->_M_detach_single(this);
-	_M_reset();
-  }
+  _M_sequence->_M_detach_single(this);
   }
 
   void
@@ -419,20 +411,32 @@ namespace __gnu_debug
   bool
   _Safe_iterator_base::
   _M_singular() const throw ()
-  { return !_M_sequence || _M_version != _M_sequence->_M_version; }
+  {
+auto seq = __atomic_load_n(&_M_sequence, __ATOMIC_ACQUIRE);
+return !seq || _M_version != seq->_M_version;
+  }
 
   bool
   _Safe_iterator_base::
   _M_can_compare(const _Safe_iterator_base& __x) const throw ()
   {
-return (!_M_singular()
-	&& !__x._M_singular() && _M_sequence == __x._M_sequence);
+auto seq = __atomic_load_n(&_M_sequence, __ATOMIC_ACQUIRE);
+if (seq && _M_version == seq->_M_version)
+  {
+	auto xseq = __atomic_load_n(&__x._M_sequence, __ATOMIC_ACQUIRE);
+	return xseq && __x._M_version == xseq->_M_version && seq == xseq;
+  }
+
+return false;
   }
 
   __gnu_cxx::__mutex&
   _Safe_iterator_base::
   _M_get_mutex() throw ()
-  { return _M_sequence->_M_get_mutex(); }
+  {
+auto seq = __atomic_load_n(&_M_sequence, __ATOMIC_ACQUIRE);
+return get_safe_base_mutex(seq);
+  }
 
   _Safe_unordered_container_base*
   _Safe_local_iterator_base::
@@ -447,11 +451,8 @@ namespace __gnu_debug
 
 // Attach to the new container (if there is one)
 if (__cont)
-  {
-	_M_sequence = __cont;
-	_M_version = _M_sequence->_M_version;
-	_M_get_container()->_M_attach_local(this, __constant);
-  }
+  static_cast<_Safe_unordered_container_base*>(__cont)
+	->_M_attach_local(this, __constant);
   }
 
   void
@@ -462,11 +463,8 @@ namespace 

Bind to std::equal plumbing in ranges::equal

2020-03-05 Thread François Dumont
I started to work on ranges::equal to find out if what I am trying to do 
is totally silly.


With this patch ranges::equal is in pare with std::equal specializations 
that is to say that it correctly deals with Debug mode or std::deque 
iterators.


Once below patch is in:

https://gcc.gnu.org/ml/libstdc++/2019-12/msg00032.html

We will even be able to call std::__equal_aux1 directly using 
__niter_base to get rid of the Debug safe iterator layer. And even in 
this case get rid of the branch __use_memcmp and leave it to __equal_aux1.


I mainly fear the usage of std::iterator_traits in __equal_aux1 to be a 
problem. Is it in this context of sized_sentinel ?


In addition to testsuite I checked running gdb that it does the right thing.

Ok to commit ?

    libstdc++ Leverage on std::equal plumbing in ranges::equal.

    Benefit from the std::equal plumbing to correctly deal with
    _GLIBCXX_DEBUG mode and std::deque iterators.

    * include/bits/ranges_algobase.h (__equal_fn::operator()):
    Review conditions to call std::__equal_aux.
    * testsuite/25_algorithms/equal/constrained.cc (test04): New.

François


diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index 80c9a774301..d4f89cb9fb2 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -82,8 +82,6 @@ namespace ranges
 		 _Iter2 __first2, _Sent2 __last2, _Pred __pred = {},
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
   {
-	// TODO: implement more specializations to at least have parity with
-	// std::equal.
 	if constexpr (__detail::__is_normal_iterator<_Iter1>
 		  || __detail::__is_normal_iterator<_Iter2>)
 	  return (*this)(std::__niter_base(std::move(__first1)),
@@ -100,19 +98,24 @@ namespace ranges
 	if (__d1 != __d2)
 	  return false;
 
+	if (!__d1)
+	  return true;
+
+	constexpr bool __is_simple_equal
+	  = (is_same_v<_Pred, ranges::equal_to>
+		 && is_same_v<_Proj1, identity>
+		 && is_same_v<_Proj2, identity>);
+	if constexpr (__is_simple_equal)
+	  {
 		using _ValueType1 = iter_value_t<_Iter1>;
 		using _ValueType2 = iter_value_t<_Iter2>;
 		constexpr bool __use_memcmp
 		  = ((is_integral_v<_ValueType1> || is_pointer_v<_ValueType1>)
-		 && __memcmpable<_Iter1, _Iter2>::__value
-		 && is_same_v<_Pred, ranges::equal_to>
-		 && is_same_v<_Proj1, identity>
-		 && is_same_v<_Proj2, identity>);
+		 && __memcmpable<_Iter1, _Iter2>::__value);
 		if constexpr (__use_memcmp)
-	  {
-		if (const size_t __len = (__last1 - __first1))
-		  return !std::__memcmp(__first1, __first2, __len);
-		return true;
+		  return !std::__memcmp(__first1, __first2, __d1);
+		else
+		  return std::__equal_aux(__first1, __first1 + __d1, __first2);
 	  }
 	else
 	  {
diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc
index 231bd8cfeaa..aa27fd195a2 100644
--- a/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc
@@ -19,6 +19,9 @@
 // { dg-do run { target c++2a } }
 
 #include 
+#include 
+#include 
+
 #include 
 #include 
 
@@ -87,10 +90,21 @@ test03()
   VERIFY( !ranges::equal(x, z) );
 }
 
+void
+test04()
+{
+  std::deque x = { {2}, {2}, {6}, {8}, {10}, {11} };
+  std::deque y = { {2}, {2}, {6}, {8}, {10}, {11} };
+  std::deque z = { {2}, {2}, {6}, {8}, {10}, {12} };
+  VERIFY( ranges::equal(x, y) );
+  VERIFY( !ranges::equal(x, z) );
+}
+
 int
 main()
 {
   test01();
   test02();
   test03();
+  test04();
 }


Bind to std::equal plumbing in ranges::equal

2020-03-05 Thread François Dumont
I started to work on ranges::equal to find out if what I am trying to do 
is totally silly.


With this patch ranges::equal is in pare with std::equal specializations 
that is to say that it correctly deals with Debug mode or std::deque 
iterators.


Once below patch is in:

https://gcc.gnu.org/ml/libstdc++/2019-12/msg00032.html

We will even be able to call std::__equal_aux1 directly using 
__niter_base to get rid of the Debug safe iterator layer. And even in 
this case get rid of the branch __use_memcmp and leave it to __equal_aux1.


In addition to testsuite I checked running gdb that it does the right thing.

Ok to commit ?

    libstdc++ Leverage on std::equal plumbing in ranges::equal.

    Benefit from the std::equal plumbing to correctly deal with
    _GLIBCXX_DEBUG mode and std::deque iterators.

    * include/bits/ranges_algobase.h (__equal_fn::operator()):
    Review conditions to call std::__equal_aux.
    * testsuite/25_algorithms/equal/constrained.cc (test04): New.

François


diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index 80c9a774301..d4f89cb9fb2 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -82,8 +82,6 @@ namespace ranges
 		 _Iter2 __first2, _Sent2 __last2, _Pred __pred = {},
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
   {
-	// TODO: implement more specializations to at least have parity with
-	// std::equal.
 	if constexpr (__detail::__is_normal_iterator<_Iter1>
 		  || __detail::__is_normal_iterator<_Iter2>)
 	  return (*this)(std::__niter_base(std::move(__first1)),
@@ -100,19 +98,24 @@ namespace ranges
 	if (__d1 != __d2)
 	  return false;
 
+	if (!__d1)
+	  return true;
+
+	constexpr bool __is_simple_equal
+	  = (is_same_v<_Pred, ranges::equal_to>
+		 && is_same_v<_Proj1, identity>
+		 && is_same_v<_Proj2, identity>);
+	if constexpr (__is_simple_equal)
+	  {
 		using _ValueType1 = iter_value_t<_Iter1>;
 		using _ValueType2 = iter_value_t<_Iter2>;
 		constexpr bool __use_memcmp
 		  = ((is_integral_v<_ValueType1> || is_pointer_v<_ValueType1>)
-		 && __memcmpable<_Iter1, _Iter2>::__value
-		 && is_same_v<_Pred, ranges::equal_to>
-		 && is_same_v<_Proj1, identity>
-		 && is_same_v<_Proj2, identity>);
+		 && __memcmpable<_Iter1, _Iter2>::__value);
 		if constexpr (__use_memcmp)
-	  {
-		if (const size_t __len = (__last1 - __first1))
-		  return !std::__memcmp(__first1, __first2, __len);
-		return true;
+		  return !std::__memcmp(__first1, __first2, __d1);
+		else
+		  return std::__equal_aux(__first1, __first1 + __d1, __first2);
 	  }
 	else
 	  {
diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc
index 231bd8cfeaa..aa27fd195a2 100644
--- a/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc
@@ -19,6 +19,9 @@
 // { dg-do run { target c++2a } }
 
 #include 
+#include 
+#include 
+
 #include 
 #include 
 
@@ -87,10 +90,21 @@ test03()
   VERIFY( !ranges::equal(x, z) );
 }
 
+void
+test04()
+{
+  std::deque x = { {2}, {2}, {6}, {8}, {10}, {11} };
+  std::deque y = { {2}, {2}, {6}, {8}, {10}, {11} };
+  std::deque z = { {2}, {2}, {6}, {8}, {10}, {12} };
+  VERIFY( ranges::equal(x, y) );
+  VERIFY( !ranges::equal(x, z) );
+}
+
 int
 main()
 {
   test01();
   test02();
   test03();
+  test04();
 }


Re: [PATCH] PR libstdc++/91620 Implement DR 526 for std::[forward_]list::remove_if/unique

2020-03-02 Thread François Dumont

Hi

    Isn't it something to fix before gcc 10 release ?

François

On 12/27/19 11:57 AM, François Dumont wrote:
Here is the patch to extend DR 526 to forward_list and list remove_if 
and unique.


As the adopted pattern is simpler I also applied it to the remove 
methods.


    PR libstdc++/91620
    * include/bits/forward_list.tcc (forward_list<>::remove): Collect 
nodes

    to destroy in an intermediate forward_list.
    (forward_list<>::remove_if, forward_list<>::unique): Likewise.
    * include/bits/list.tcc (list<>::remove, list<>::unique): Likewise.
    (list<>::remove_if): Likewise.
    * include/debug/forward_list (forward_list<>::_M_erase_after): 
Remove.

    (forward_list<>::erase_after): Adapt.
    (forward_list<>::remove, forward_list<>::remove_if): Collect nodes to
    destroy in an intermediate forward_list.
    (forward_list<>::unique): Likewise.
    * include/debug/list (list<>::remove, list<>::unique): Likewise.
    (list<>::remove_if): Likewise.

Tested under Linux x86_64 normal and debug modes.

Ok to commit ?

François





[PATCH] Limit includes in hashtable_policy.h

2020-02-27 Thread François Dumont
When I use std::is_permutation in hashtable_policy.h I included 
stl_algo.h which is a large header. No other header in include/bits does 
this, I would prefer not being the first to do such a thing.


As it is a recent change I prefer to submit this patch now.

Git commit message:

    libstdc++ Hashtable: Move std::is_permutation to limit includes

    * include/bits/stl_algo.h (__find_if, __count_if, 
std::is_permutation): Move...

    * include/bits/stl_algobase.h: ...here.
    * include/bits/hashtable_policy.h: Remove  include.

testsuite/23_containers/unordered* tested under Linux x86_64, I'll run 
full before any commit.


Ok to commit now ?

Ok to commit once back in stage 1 ?

François

diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h
index 22bc4472e32..ef120134914 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -33,8 +33,7 @@
 
 #include 		// for std::tuple, std::forward_as_tuple
 #include 		// for std::numeric_limits
-#include 	// for std::min.
-#include 	// for std::is_permutation.
+#include 	// for std::min, std::is_permutation.
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h
index 6503d1518d3..932ece55529 100644
--- a/libstdc++-v3/include/bits/stl_algo.h
+++ b/libstdc++-v3/include/bits/stl_algo.h
@@ -96,76 +96,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	std::iter_swap(__result, __b);
 }
 
-  /// This is an overload used by find algos for the Input Iterator case.
-  template
-_GLIBCXX20_CONSTEXPR
-inline _InputIterator
-__find_if(_InputIterator __first, _InputIterator __last,
-	  _Predicate __pred, input_iterator_tag)
-{
-  while (__first != __last && !__pred(__first))
-	++__first;
-  return __first;
-}
-
-  /// This is an overload used by find algos for the RAI case.
-  template
-_GLIBCXX20_CONSTEXPR
-_RandomAccessIterator
-__find_if(_RandomAccessIterator __first, _RandomAccessIterator __last,
-	  _Predicate __pred, random_access_iterator_tag)
-{
-  typename iterator_traits<_RandomAccessIterator>::difference_type
-	__trip_count = (__last - __first) >> 2;
-
-  for (; __trip_count > 0; --__trip_count)
-	{
-	  if (__pred(__first))
-	return __first;
-	  ++__first;
-
-	  if (__pred(__first))
-	return __first;
-	  ++__first;
-
-	  if (__pred(__first))
-	return __first;
-	  ++__first;
-
-	  if (__pred(__first))
-	return __first;
-	  ++__first;
-	}
-
-  switch (__last - __first)
-	{
-	case 3:
-	  if (__pred(__first))
-	return __first;
-	  ++__first;
-	case 2:
-	  if (__pred(__first))
-	return __first;
-	  ++__first;
-	case 1:
-	  if (__pred(__first))
-	return __first;
-	  ++__first;
-	case 0:
-	default:
-	  return __last;
-	}
-}
-
-  template
-_GLIBCXX20_CONSTEXPR
-inline _Iterator
-__find_if(_Iterator __first, _Iterator __last, _Predicate __pred)
-{
-  return __find_if(__first, __last, __pred,
-		   std::__iterator_category(__first));
-}
-
   /// Provided for stable_partition to use.
   template
 _GLIBCXX20_CONSTEXPR
@@ -3279,18 +3209,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  __new_value);
 }
 
-  template
-_GLIBCXX20_CONSTEXPR
-typename iterator_traits<_InputIterator>::difference_type
-__count_if(_InputIterator __first, _InputIterator __last, _Predicate __pred)
-{
-  typename iterator_traits<_InputIterator>::difference_type __n = 0;
-  for (; __first != __last; ++__first)
-	if (__pred(__first))
-	  ++__n;
-  return __n;
-}
-
 #if __cplusplus >= 201103L
   /**
*  @brief  Determines whether the elements of a sequence are sorted.
@@ -3588,74 +3506,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   return std::make_pair(*__p.first, *__p.second);
 }
 
-  template
-_GLIBCXX20_CONSTEXPR
-bool
-__is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1,
-		 _ForwardIterator2 __first2, _BinaryPredicate __pred)
-{
-  // Efficiently compare identical prefixes:  O(N) if sequences
-  // have the same elements in the same order.
-  for (; __first1 != __last1; ++__first1, (void)++__first2)
-	if (!__pred(__first1, __first2))
-	  break;
-
-  if (__first1 == __last1)
-	return true;
-
-  // Establish __last2 assuming equal ranges by iterating over the
-  // rest of the list.
-  _ForwardIterator2 __last2 = __first2;
-  std::advance(__last2, std::distance(__first1, __last1));
-  for (_ForwardIterator1 __scan = __first1; __scan != __last1; ++__scan)
-	{
-	  if (__scan != std::__find_if(__first1, __scan,
-			  __gnu_cxx::__ops::__iter_comp_iter(__pred, __scan)))
-	continue; // We've seen this one before.
-	  
-	  auto __matches
-	= std::__count_if(__first2, __last2,
-			__gnu_cxx::__ops::__iter_comp_iter(__pred, __scan));
-	  if (0 == __matches ||
-	  

Re: [PATCH 2/3] libstdc++: Implement C++20 constrained algorithms

2020-02-05 Thread François Dumont

Hi

    Is it me or the patch isn't an attachment ? It is far more 
convenient to provide something easy to extract and apply locally.


On 2/4/20 3:07 AM, Patrick Palka wrote:

This patch implements the C++20 ranges overloads for the algorithms in
[algorithms].  Most of the algorithms were reimplemented, with each of their
implementations very closely following the existing implementation in
bits/stl_algo.h and bits/stl_algobase.h.  The reason for reimplementing most of
the algorithms instead of forwarding to their STL-style overload is because
forwarding cannot be conformantly and efficiently performed for algorithms that
operate on non-random-access iterators.  But algorithms that operate on random
access iterators can safely and efficiently be forwarded to the STL-style
implementation, and this patch does so for push_heap, pop_heap, make_heap,
sort_heap, sort, stable_sort, nth_element, inplace_merge and stable_partition.

What's missing from this patch is debug-iterator


Always the 5th wheel of the car like we say in French :-)

I'll be looking at this point once I manage to apply the patch.


  and container specializations
that are present for some of the STL-style algorithms that need to be ported
over to the ranges algos.  I marked them missing at TODO comments.  There are
also some other minor outstanding TODOs.

The code that could use the most thorough review is ranges::__copy_or_move,
ranges::__copy_or_move_backward, ranges::__equal and
ranges::__lexicographical_compare.  In the tests, I tried to test the interface
of each new overload, as well as the correctness of the new implementation.

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
new file mode 100644
index 000..2e177ce7f7a
--- /dev/null
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -0,0 +1,3640 @@
+// Core algorithmic facilities -*- C++ -*-
+
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.


Copyright for new files is wrong, should be only 2020. I know it is 
painful to maintain that when you work on patch on several years.




+//
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// .
+
+/** @file bits/ranges_algo.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{algorithm}
+ */
+
+#ifndef _RANGES_ALGO_H
+#define _RANGES_ALGO_H 1
+
+#if __cplusplus > 201703L
+
+#include 
+#include 
+#include 
+// #include 
+#include 
+#include 
+#include  // __is_byte
+#include  // concept uniform_random_bit_generator
+
+#if __cpp_lib_concepts
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace ranges
+{
+  namespace __detail
+  {
+template
+constexpr inline bool __is_normal_iterator = false;
+
+template
+constexpr inline bool
+  __is_normal_iterator<__gnu_cxx::__normal_iterator<_Iterator, _Container>>
+  = true;
+
+template
+constexpr inline bool __is_reverse_iterator = false;
+
+template
+constexpr inline bool
+  __is_reverse_iterator> = true;
+
+template
+constexpr inline bool __is_move_iterator = false;
+
+template
+constexpr inline bool
+  __is_move_iterator> = true;


Did you consider the __is_move_iterator in stl_iterator.h ?

At least this version will also detect a move_iterator in different 
situation. I haven't check yet what you are doing with that but it might 
be an easy way to get better debug iterators integration for instance.


François


[PATCH] Hashtable: Add missing std qualification on a forward call

2020-02-11 Thread François Dumont

I just notice that in a recent patch I forgot a std:: on a call to forward.

* include/bits/hashtable.h (_Hashtable<>(_Hashtable&&, 
std::allocator_type&)):

    Add missing std namespace qualification to forward call.

Ok to commit ?

François

diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 9e721aad8cc..b00319a668b 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -1371,7 +1371,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  using _Fwd_Ht = typename
 	conditional<__move_if_noexcept_cond::value,
 			const _Hashtable&, _Hashtable&&>::type;
-	  _M_assign(forward<_Fwd_Ht>(__ht), __alloc_gen);
+	  _M_assign(std::forward<_Fwd_Ht>(__ht), __alloc_gen);
 	  __ht.clear();
 	}
 }


Re: [PATCH 2/3] libstdc++: Implement C++20 constrained algorithms

2020-02-13 Thread François Dumont

Thanks for those additional information.

I still think that the same way we rely on STL algos for 
push_heap/pop_heap/... we should do it for copy/move/... from 
stl_algobase.h for RAI.


In fact range algos that are already trying to call C functions should 
just try to call the STL counterparts which will then forward to C 
functions.


On 2/13/20 8:00 PM, Jonathan Wakely wrote:

On 13/02/20 19:07 +0100, François Dumont wrote:

On 2/4/20 3:07 AM, Patrick Palka wrote:

This patch implements the C++20 ranges overloads for the algorithms in
[algorithms].  Most of the algorithms were reimplemented, with each 
of their

implementations very closely following the existing implementation in
bits/stl_algo.h and bits/stl_algobase.h.  The reason for 
reimplementing most of
the algorithms instead of forwarding to their STL-style overload is 
because
forwarding cannot be conformantly and efficiently performed for 
algorithms that

operate on non-random-access iterators.

Why ? Do you have a clear counter-example ?

Maybe at the time you wrote this code those algos were not constexpr 
qualified, but they are now.


It has nothing to do with constexpr.

If you call a ranges algo with an iterator and a sentinel that is a
different type to the iterator, you can't call the old STL algo unless
you can efficiently get an end iterator that refers to the same
position as the sentinel. For random access iterators that is:

auto last2 = first + (last - first);

But for non-random access iterators finding the distance between first
and last is not possible in O(1), and incrementing first by that
distance is also not possible in O(1).


  But algorithms that operate on random
access iterators can safely and efficiently be forwarded to the 
STL-style
implementation, and this patch does so for push_heap, pop_heap, 
make_heap,
sort_heap, sort, stable_sort, nth_element, inplace_merge and 
stable_partition.
IMHO we should try as much as possible to forward to algos in 
stl_algobase.h.


That would not be conforming in many cases.

The old code assumes iterators can be copied. It assumes they have an
iterator_category. It assumes they have operator->(). Most
importantly, it assumes the begin and end iterators have the same
type.

The old algorithms do tag dispatching, which adds function call
overhead at run-time and overload resolution overhead at compile-time.

The new constrained algos can be implemented much more cleanly using
if-constexpr and the new iterator concepts.

There are very good reasons to reimplement the new ranges algos.

Those are highly customized and will be even more in the future when 
some patches I have on my side will be integrated (I hope).


If you do so you won't have to care much about _GLIBCXX_DEBUG iterators.



What's missing from this patch is debug-iterator and container 
specializations
that are present for some of the STL-style algorithms that need to 
be ported
over to the ranges algos.  I marked them missing at TODO comments.  
There are

also some other minor outstanding TODOs.

The code that could use the most thorough review is 
ranges::__copy_or_move,

ranges::__copy_or_move_backward, ranges::__equal and
ranges::__lexicographical_compare.  In the tests, I tried to test 
the interface
of each new overload, as well as the correctness of the new 
implementation.










Re: [PATCH 2/3] libstdc++: Implement C++20 constrained algorithms

2020-02-13 Thread François Dumont

On 2/4/20 3:07 AM, Patrick Palka wrote:

This patch implements the C++20 ranges overloads for the algorithms in
[algorithms].  Most of the algorithms were reimplemented, with each of their
implementations very closely following the existing implementation in
bits/stl_algo.h and bits/stl_algobase.h.  The reason for reimplementing most of
the algorithms instead of forwarding to their STL-style overload is because
forwarding cannot be conformantly and efficiently performed for algorithms that
operate on non-random-access iterators.

Why ? Do you have a clear counter-example ?

Maybe at the time you wrote this code those algos were not constexpr 
qualified, but they are now.



   But algorithms that operate on random
access iterators can safely and efficiently be forwarded to the STL-style
implementation, and this patch does so for push_heap, pop_heap, make_heap,
sort_heap, sort, stable_sort, nth_element, inplace_merge and stable_partition.
IMHO we should try as much as possible to forward to algos in 
stl_algobase.h.


Those are highly customized and will be even more in the future when 
some patches I have on my side will be integrated (I hope).


If you do so you won't have to care much about _GLIBCXX_DEBUG iterators.



What's missing from this patch is debug-iterator and container specializations
that are present for some of the STL-style algorithms that need to be ported
over to the ranges algos.  I marked them missing at TODO comments.  There are
also some other minor outstanding TODOs.

The code that could use the most thorough review is ranges::__copy_or_move,
ranges::__copy_or_move_backward, ranges::__equal and
ranges::__lexicographical_compare.  In the tests, I tried to test the interface
of each new overload, as well as the correctness of the new implementation.





Re: [PATCH] libstdc++/91223 Improve unordered containers == operator

2020-01-15 Thread François Dumont

On 1/15/20 10:52 PM, Jonathan Wakely wrote:

On 15/01/20 21:48 +, Jonathan Wakely wrote:

On 14/01/20 22:25 +0100, François Dumont wrote:

On 1/13/20 10:53 PM, Jonathan Wakely wrote:

On 13/01/20 22:41 +0100, François Dumont wrote:


For the multi-keys we could still avoid redundant comparisons when 
_Equal is just doing == on the key type. On unordered_multiset we 
could just avoids the call to is_permuation and on the 
unordered_multimap we could check the is_permutation only on the 
associated value rather than on the std::pair.



I don't think that's necessary, or helpful.

The idea of https://gcc.gnu.org/ml/libstdc++/2020-01/msg00070.html is
that you shouldn't be using _Equal at all, and therefore it doesn't
matter whether it's std::equal_to or not.



And it was indeed possible.


Nice!


    PR libstdc++/91223
    * include/bits/hashtable.h (_Hashtable<>): Make _Equality<> friend.
    * include/bits/hashtable_policy.h: Include .
    (_Equality_base): Remove.
    (_Equality<>::_M_equal): Review implementation. Use 
std::is_permutation.

    * testsuite/23_containers/unordered_multiset/operators/1.cc
    (Hash, Equal, test02, test03): New.
    * testsuite/23_containers/unordered_set/operators/1.cc
    (Hash, Equal, test02, test03): New.

Tested under Linux x86_64.

Ok to commit ?


Yes, OK for trunk (we're in stage4 but your patch was posted in stage3
and fixes a pretty nasty performance bug, so is OK now).

N.B. GCC has moved to Git instead of Subversion. If you don't have Git
access set up let me know and I can commit the patch for you.


I haven't done the move yet and won't be able to do it before the 
week-end. So please proceed to the commit for me, thanks.




P.S. some performance numbers using the code in the bug report
(calling Nested(n+1) and Nested(n) where n is the number of levels
shown) ...

Before:

10 levels of nesting, 0.90 seconds
20 levels of nesting, 0.082400 seconds
22 levels of nesting, 0.285758 seconds
24 levels of nesting, 1.146782 seconds
26 levels of nesting, 4.659524 seconds
28 levels of nesting, 17.739022 seconds
30 levels of nesting, 76.288977 seconds

real    1m40.204s
user    1m40.039s
sys 0m0.005s

After:

10 levels of nesting, 0.01 seconds
20 levels of nesting, 0.01 seconds
22 levels of nesting, 0.01 seconds
24 levels of nesting, 0.01 seconds
26 levels of nesting, 0.01 seconds
28 levels of nesting, 0.01 seconds
30 levels of nesting, 0.01 seconds
2 levels of nesting, 0.002905 seconds

real    0m0.002s
user    0m0.001s
sys 0m0.001s


Very nice indeed !



Re: [PATCH] libstdc++/91223 Improve unordered containers == operator

2020-01-13 Thread François Dumont

On 1/10/20 11:01 PM, Jonathan Wakely wrote:

On 10/01/20 18:54 +0100, François Dumont wrote:

Hi

    Here is my attempt to improve == operator.

    There is a small optimization for the std::unordered_mutiXXX 
containers but the main enhancement rely on some partial template 
specialization of the _Equality type. I limit it to usage of 
unordered containers with std::equal_to to be sure that the container 
_Equal functor is like the key type ==.


I think we can assume that for any _Equal, not just std::equal_to:
http://eel.is/c++draft/unord.req#12.sentence-5

However ...


Ok but...



    Do I need to also consider user partial template specialization 
of std::equal_to ? It is a well know bad practice so I hope the 
Standard says that such a partial specialization leads to undefined 
behavior.


It's certainly not undefined to specialize equal_to, and I'm not sure
how to make your optimisations valid in that case.


This proposal is indeed invalid if you use a std::equal_to partial 
specialization, this is why I asked.




Consider:

struct X
{
  int i;
  int rounded() const { return i - (i % 10); }
  bool operator==(X x) const { return i == x.i; }
};

template<> struct std::equal_to
{
  bool operator()(X l, X r) const
  { return l.rounded() == r.rounded(); }
};

template<> std::hash
{
  bool operator()(X x) const { return hash()(x.rounded()); }
};

std::unordered_multiset u{ X{10}, X{11}, X{12} };
std::unordered_multiset v{ X{15}, X{16}, X{17} };
bool b1 = u == v;
bool b2 = std::is_permutation(u.begin(), u.end(), v.begin());
assert(b1 == b2);

I think the last new specialization in your patch would be used for
this case, and because __x_count == v.count(*u.begin()) it will say
they're equal. But the is_permutation call says they're not.

So I think the assertion would fail, but the standard says it should
pass. Am I mistaken?


I agree, it would fail and the Standard says it should pass.

So here is a new proposal. For the unique keys case I think we are good, 
I do not see any other optimization.


For the multi-keys we could still avoid redundant comparisons when 
_Equal is just doing == on the key type. On unordered_multiset we could 
just avoids the call to is_permuation and on the unordered_multimap we 
could check the is_permutation only on the associated value rather than 
on the std::pair.


In order to detect that _Equal is the std::equal_to from stl_function.h 
it would be great to have something like a __builtin_is_system returning 
true for types defined in system headers. For now I try to propose 
something similar without compiler help.


François


diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 8fac385570b..9e721aad8cc 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -337,6 +337,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	   bool _Constant_iteratorsa>
 	friend struct __detail::_Insert;
 
+  template
+	friend struct __detail::_Equality;
+
 public:
   using size_type = typename __hashtable_base::size_type;
   using difference_type = typename __hashtable_base::difference_type;
diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h
index 7bbfdfd375b..55c020f93d1 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -34,6 +34,7 @@
 #include 		// for std::tuple, std::forward_as_tuple
 #include 		// for std::numeric_limits
 #include 	// for std::min.
+#include 	// for std::is_permutation.
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -1815,65 +1816,6 @@ namespace __detail
 _M_eq() const { return _EqualEBO::_M_cget(); }
   };
 
-  /**
-   *  struct _Equality_base.
-   *
-   *  Common types and functions for class _Equality.
-   */
-  struct _Equality_base
-  {
-  protected:
-template
-  static bool
-  _S_is_permutation(_Uiterator, _Uiterator, _Uiterator);
-  };
-
-  // See std::is_permutation in N3068.
-  template
-bool
-_Equality_base::
-_S_is_permutation(_Uiterator __first1, _Uiterator __last1,
-		  _Uiterator __first2)
-{
-  for (; __first1 != __last1; ++__first1, ++__first2)
-	if (!(*__first1 == *__first2))
-	  break;
-
-  if (__first1 == __last1)
-	return true;
-
-  _Uiterator __last2 = __first2;
-  std::advance(__last2, std::distance(__first1, __last1));
-
-  for (_Uiterator __it1 = __first1; __it1 != __last1; ++__it1)
-	{
-	  _Uiterator __tmp =  __first1;
-	  while (__tmp != __it1 && !bool(*__tmp == *__it1))
-	++__tmp;
-
-	  // We've seen this one before.
-	  if (__tmp != __it1)
-	continue;
-
-	  std::ptrdiff_t __n2 = 0;
-	  for (__tmp = __first2; __tmp != __last2; ++__tmp)
-	if (*__tmp == *__it1)
-	  ++__n2;
-
-	  if (!__n2)
-	return false;
-
-	  std::ptrdiff_t __n1 = 0;
-	  for (__tmp = __it1; __tmp != __last1; ++__tmp)
-	if (*__tmp == *__it1)
-	 

Re: [PATCH] libstdc++/91223 Improve unordered containers == operator

2020-01-14 Thread François Dumont

On 1/13/20 10:53 PM, Jonathan Wakely wrote:

On 13/01/20 22:41 +0100, François Dumont wrote:


For the multi-keys we could still avoid redundant comparisons when 
_Equal is just doing == on the key type. On unordered_multiset we 
could just avoids the call to is_permuation and on the 
unordered_multimap we could check the is_permutation only on the 
associated value rather than on the std::pair.



I don't think that's necessary, or helpful.

The idea of https://gcc.gnu.org/ml/libstdc++/2020-01/msg00070.html is
that you shouldn't be using _Equal at all, and therefore it doesn't
matter whether it's std::equal_to or not.



And it was indeed possible.

    PR libstdc++/91223
    * include/bits/hashtable.h (_Hashtable<>): Make _Equality<> friend.
    * include/bits/hashtable_policy.h: Include .
    (_Equality_base): Remove.
    (_Equality<>::_M_equal): Review implementation. Use 
std::is_permutation.

    * testsuite/23_containers/unordered_multiset/operators/1.cc
    (Hash, Equal, test02, test03): New.
    * testsuite/23_containers/unordered_set/operators/1.cc
    (Hash, Equal, test02, test03): New.

Tested under Linux x86_64.

Ok to commit ?

François

diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 8fac385570b..9e721aad8cc 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -337,6 +337,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	   bool _Constant_iteratorsa>
 	friend struct __detail::_Insert;
 
+  template
+	friend struct __detail::_Equality;
+
 public:
   using size_type = typename __hashtable_base::size_type;
   using difference_type = typename __hashtable_base::difference_type;
diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h
index 7bbfdfd375b..4024e6c37fa 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -34,6 +34,7 @@
 #include 		// for std::tuple, std::forward_as_tuple
 #include 		// for std::numeric_limits
 #include 	// for std::min.
+#include 	// for std::is_permutation.
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -1815,65 +1816,6 @@ namespace __detail
 _M_eq() const { return _EqualEBO::_M_cget(); }
   };
 
-  /**
-   *  struct _Equality_base.
-   *
-   *  Common types and functions for class _Equality.
-   */
-  struct _Equality_base
-  {
-  protected:
-template
-  static bool
-  _S_is_permutation(_Uiterator, _Uiterator, _Uiterator);
-  };
-
-  // See std::is_permutation in N3068.
-  template
-bool
-_Equality_base::
-_S_is_permutation(_Uiterator __first1, _Uiterator __last1,
-		  _Uiterator __first2)
-{
-  for (; __first1 != __last1; ++__first1, ++__first2)
-	if (!(*__first1 == *__first2))
-	  break;
-
-  if (__first1 == __last1)
-	return true;
-
-  _Uiterator __last2 = __first2;
-  std::advance(__last2, std::distance(__first1, __last1));
-
-  for (_Uiterator __it1 = __first1; __it1 != __last1; ++__it1)
-	{
-	  _Uiterator __tmp =  __first1;
-	  while (__tmp != __it1 && !bool(*__tmp == *__it1))
-	++__tmp;
-
-	  // We've seen this one before.
-	  if (__tmp != __it1)
-	continue;
-
-	  std::ptrdiff_t __n2 = 0;
-	  for (__tmp = __first2; __tmp != __last2; ++__tmp)
-	if (*__tmp == *__it1)
-	  ++__n2;
-
-	  if (!__n2)
-	return false;
-
-	  std::ptrdiff_t __n1 = 0;
-	  for (__tmp = __it1; __tmp != __last1; ++__tmp)
-	if (*__tmp == *__it1)
-	  ++__n1;
-
-	  if (__n1 != __n2)
-	return false;
-	}
-  return true;
-}
-
   /**
*  Primary class template  _Equality.
*
@@ -1889,7 +1831,7 @@ namespace __detail
 	   bool _Unique_keys = _Traits::__unique_keys::value>
 struct _Equality;
 
-  /// Specialization.
+  /// unordered_map and unordered_set specializations.
   template::
 _M_equal(const __hashtable& __other) const
 {
+  using __node_base = typename __hashtable::__node_base;
+  using __node_type = typename __hashtable::__node_type;
   const __hashtable* __this = static_cast(this);
-
   if (__this->size() != __other.size())
 	return false;
 
   for (auto __itx = __this->begin(); __itx != __this->end(); ++__itx)
 	{
-	  const auto __ity = __other.find(_ExtractKey()(*__itx));
-	  if (__ity == __other.end() || !bool(*__ity == *__itx))
+	  std::size_t __ybkt = __other._M_bucket_index(__itx._M_cur);
+	  __node_base* __prev_n = __other._M_buckets[__ybkt];
+	  if (!__prev_n)
 	return false;
+
+	  for (__node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt);;
+	   __n = __n->_M_next())
+	{
+	  if (__n->_M_v() == *__itx)
+		break;
+
+	  if (!__n->_M_nxt
+		  || __other._M_bucket_index(__n->_M_next()) != __ybkt)
+		return false;
+	}
 	}
+
   return true;
 }
 
-  /// Specialization.
+  /// unordered_multiset and unordered_multimap specializations.
 

Re: [PATCH] libstdc++/91223 Improve unordered containers == operator

2020-01-16 Thread François Dumont

On 1/16/20 5:01 PM, Jonathan Wakely wrote:

On 16/01/20 13:25 +, Jonathan Wakely wrote:

On 16/01/20 07:42 +0100, François Dumont wrote:

On 1/15/20 10:52 PM, Jonathan Wakely wrote:

On 15/01/20 21:48 +, Jonathan Wakely wrote:

On 14/01/20 22:25 +0100, François Dumont wrote:

On 1/13/20 10:53 PM, Jonathan Wakely wrote:

On 13/01/20 22:41 +0100, François Dumont wrote:


For the multi-keys we could still avoid redundant comparisons 
when _Equal is just doing == on the key type. On 
unordered_multiset we could just avoids the call to 
is_permuation and on the unordered_multimap we could check the 
is_permutation only on the associated value rather than on the 
std::pair.



I don't think that's necessary, or helpful.

The idea of 
https://gcc.gnu.org/ml/libstdc++/2020-01/msg00070.html is

that you shouldn't be using _Equal at all, and therefore it doesn't
matter whether it's std::equal_to or not.



And it was indeed possible.


Nice!


    PR libstdc++/91223
    * include/bits/hashtable.h (_Hashtable<>): Make _Equality<> 
friend.

    * include/bits/hashtable_policy.h: Include .
    (_Equality_base): Remove.
    (_Equality<>::_M_equal): Review implementation. Use 
std::is_permutation.

    * testsuite/23_containers/unordered_multiset/operators/1.cc
    (Hash, Equal, test02, test03): New.
    * testsuite/23_containers/unordered_set/operators/1.cc
    (Hash, Equal, test02, test03): New.

Tested under Linux x86_64.

Ok to commit ?


Yes, OK for trunk (we're in stage4 but your patch was posted in 
stage3

and fixes a pretty nasty performance bug, so is OK now).

N.B. GCC has moved to Git instead of Subversion. If you don't have 
Git

access set up let me know and I can commit the patch for you.


I haven't done the move yet and won't be able to do it before the 
week-end. So please proceed to the commit for me, thanks.


No problem, I can do that.


Your patch is now committed to trunk. Thanks for the major
improvement.

I had a look at std::is_permutation and I think we can make some
simplifications to the 4-argument overload, and we can share most of
the code between the 3-arg and 4-arg overloads (once they've confirmed
the lengths are the same they do exactly the same thing). See the
attached patch. This should probably wait for stage1 though.

I also wanted to add some comments to the _Equality::_M_equal
specialiation for unordered_multimap/multiset to explain what the code
was doing, and had some more ideas. See patch again.

It looks like this loop can potentially visit every element of
__other, instead of stopping at the end of the bucket:

  typename __hashtable::const_iterator __ity(__y_n);
  for (auto __ity_end = __ity; __ity_end != __other.end(); ++__ity_end)
    if (--__x_count == 0)
  break;

Consider a case like this:

unordered_multiset a{1, 2, 3, 4};
for (int i = 0; i <1; ++i)
  a.insert(1);
unordered_multiset b{1, 2, 3, 4};
for (int i = 0; i <1; ++i)
  b.insert(2);

When doing a == b we'll find 1 elements in a with key '1',
and find one element in b with that key. But then we iterate through
every element in b after that one, even though they have different
keys and are probably in different buckets.

Instead of just iterating from __ity to __other.end(), can we use a
local iterator so we stop at the end of the bucket?

This seems to make the PR91263 example *very* slightly slower, but
makes the example above significantly faster.

What do you think?


The hashtable implementation is doing its best to provide good 
performances as long as the user does its part of the job. Mainly 
provide a good hash to distrubute elements smoothly throughout the 
buckets. But also avoid this kind of unordered_multiset.


If you check if you don't move out of bucket you'll have to pay for the 
bucket computation (subject of PR 68303) or perform a redundant _Equal 
to check when we left the range of equivalent elements like it used to 
be done. Current implementation leave it to the std::is_permutation to 
do that which in normal situation will be better I think.





Re: Deque rotate on current node

2020-01-16 Thread François Dumont
After the recent optimization that went in despite in stage 4 I wonder 
why I never got any feedback for this one.


https://gcc.gnu.org/ml/libstdc++/2019-05/msg00166.html

I forgot to note that this is the simplest reply to an old Paolo's 
request to recycle std::deque's "nodes". And this one is abi compatible !


François

On 5/20/19 7:39 AM, François Dumont wrote:

Hi

  std::deque is supposed to be like a double-queue that you can attack 
from front and back. But currrently its implementation makes it behave 
differently when starting from a fresh deque. If push_back then all 
goes well, it is copy/move to the current internal 'node'. If 
push_front then a new 'node' is created and on next pop_back the 
initial node will be deallocated without having ever be used.


  This patch changes this behavior. As long as deque is empty we can 
play with its state to make it push_back- or push_front-ready. It will 
also benefit to the usage of deque in the std::stack.


  More generally it could really improve scenario in which deque is 
used as queue of elements exchanged between different threads. As you 
need to make sure that consumers are faster than producers then your 
deque should remain empty most of the time and so this proposed patch 
should avoid nodes to be allocated/deallocated all the time.


    * include/bits/deque.tcc (deque<>::_M_push_back_aux):
    Rotate on current node if deque is empty.
    (deue<>::_M_push_front_aux): Likewise.

Tested under Linux x86_64, ok to commit ?

François





Re: Deque rotate on current node

2020-01-17 Thread François Dumont

On 1/17/20 11:01 AM, Jonathan Wakely wrote:

On 20/05/19 07:39 +0200, François Dumont wrote:

Hi

  std::deque is supposed to be like a double-queue that you can 
attack from front and back. But currrently its implementation makes 
it behave differently when starting from a fresh deque. If push_back 
then all goes well, it is copy/move to the current internal 'node'. 
If push_front then a new 'node' is created and on next pop_back the 
initial node will be deallocated without having ever be used.


  This patch changes this behavior. As long as deque is empty we can 
play with its state to make it push_back- or push_front-ready. It 
will also benefit to the usage of deque in the std::stack.


  More generally it could really improve scenario in which deque is 
used as queue of elements exchanged between different threads. As you 
need to make sure that consumers are faster than producers then your 
deque should remain empty most of the time and so this proposed patch 
should avoid nodes to be allocated/deallocated all the time.


This benefits the case where you always push at the same end. But with
your patch if I do push_front then push_back,
we still allocate a second node even though the first one is nearly
empty.

Would it be better to point into the middle of the node, not right at
the end or right at the beginning?


That's purely empirical but I tend to think that when you need push_back 
only you go with std::vector or std::deque, when you need push_front 
only you go with std::deque and when you need both you go with 
std::list. At least std::stack and std::queue are following this axiom 
per default.


The tradeoff you are describing is not worst than current situation 
where you will eventually deallocate a node that you haven't used at all.


Are you proposing to just init in the middle or also to always reset 
when empty in the middle ? If we also reset in the middle those doing 
always push_back or push_front will live with half a node unreachable.


We could just init in the middle however. It would be a different patch 
as this one is focus on just recycling the last empty node.


I consider adding a flag keeping the info that the deque is 
push_back|push_front|both-oriented updated based on its usage but I 
doubt it would worth it. Moreover it would introduce an abi breakage.





    * include/bits/deque.tcc (deque<>::_M_push_back_aux):
    Rotate on current node if deque is empty.
    (deue<>::_M_push_front_aux): Likewise.

Tested under Linux x86_64, ok to commit ?

François



diff --git a/libstdc++-v3/include/bits/deque.tcc 
b/libstdc++-v3/include/bits/deque.tcc

index 2053afe1d69..245e3e712d8 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -507,6 +507,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
  _M_push_back_aux(const value_type& __t)
#endif
  {
+    if (empty())
+  {
+    // Move iterators to point to the current node begin.
+    this->_M_impl._M_start._M_cur = 
this->_M_impl._M_start._M_first;
+    this->_M_impl._M_finish._M_cur = 
this->_M_impl._M_finish._M_first;

+#if __cplusplus >= 201103L
+    emplace_back(std::forward<_Args>(__args)...);
+#else
+    push_back(__t);
+#endif
+    return;
+  }
+
if (size() == max_size())
  __throw_length_error(
  __N("cannot create std::deque larger than max_size()"));
@@ -546,6 +559,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
  _M_push_front_aux(const value_type& __t)
#endif
  {
+    if (empty())
+  {
+    // Move iterators to point to the current node end.
+    this->_M_impl._M_finish._M_cur = 
this->_M_impl._M_finish._M_last - 1;
+    this->_M_impl._M_start._M_cur = 
this->_M_impl._M_start._M_last - 1;

+#if __cplusplus >= 201103L
+    emplace_front(std::forward<_Args>(__args)...);
+#else
+    push_front(__t);
+#endif
+    return;
+  }
+
if (size() == max_size())
  __throw_length_error(
  __N("cannot create std::deque larger than max_size()"));






[PATCH] libstdc++/91223 Improve unordered containers == operator

2020-01-10 Thread François Dumont

Hi

    Here is my attempt to improve == operator.

    There is a small optimization for the std::unordered_mutiXXX 
containers but the main enhancement rely on some partial template 
specialization of the _Equality type. I limit it to usage of unordered 
containers with std::equal_to to be sure that the container _Equal 
functor is like the key type ==.


    Do I need to also consider user partial template specialization of 
std::equal_to ? It is a well know bad practice so I hope the Standard 
says that such a partial specialization leads to undefined behavior.


    I saw that the _S_is_permutation has been done in 2012, before 
std::is_permutation has been added in 2013. I'll try to replace it in a 
future patch.


    PR libstdc++/91223
    * include/bits/hashtable_policy.h
    (_Equality<_Key, std::pair, _Alloc,
    __detail::_Select1st, std::equal_to<_Key>, _H1, _H2, _Hash,
    _RehashPolicy, _Traits, true>): New partial template spetialization.
    (_Equality<_Value, _Value, _Alloc, __detail::_Identity,
    std::equal_to<_Value>, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>):
    Likewise.
    (_Equality<_Key, std::pair, _Alloc,
    __detail::_Select1st, std::equal_to<_Key>, _H1, _H2, _Hash,
    _RehashPolicy, _Traits, false>): Likewise.
    (_Equality<_Key, std::pair, _Alloc,
    __detail::_Select1st, std::equal_to<_Key>, _H1, _H2, _Hash)
    (_RehashPolicy, _Traits, false>): Likewise.
    * src/c++11/hashtable_c++0x.cc: Include .
    * testsuite/23_containers/unordered_multiset/operators/1.cc
    (Hash, Equal, test02, test03): New.
    * testsuite/23_containers/unordered_set/operators/1.cc
    (Hash, Equal, test02, test03): New.

unordered tests run under Linux x86_64.

Ok to commit after running all tests ?

François

diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h
index 7bbfdfd375b..2ac3e959320 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -1959,11 +1959,18 @@ namespace __detail
 
   for (auto __itx = __this->begin(); __itx != __this->end();)
 	{
-	  const auto __xrange = __this->equal_range(_ExtractKey()(*__itx));
+	  std::size_t __x_count = 1;
+	  auto __itx_end = __itx;
+	  for (++__itx_end; __itx_end != __this->end()
+		 && __this->key_eq()(_ExtractKey()(*__itx_end),
+ _ExtractKey()(*__itx));
+	   ++__itx_end)
+	++__x_count;
+
+	  const auto __xrange = std::make_pair(__itx, __itx_end);
 	  const auto __yrange = __other.equal_range(_ExtractKey()(*__itx));
 
-	  if (std::distance(__xrange.first, __xrange.second)
-	  != std::distance(__yrange.first, __yrange.second))
+	  if (__x_count != std::distance(__yrange.first, __yrange.second))
 	return false;
 
 	  if (!_S_is_permutation(__xrange.first, __xrange.second,
@@ -1975,6 +1982,242 @@ namespace __detail
   return true;
 }
 
+  /// Specialization.
+  template
+struct _Equality<_Key, std::pair, _Alloc,
+		 __detail::_Select1st, std::equal_to<_Key>,
+		 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>
+{
+  using __hashtable = _Hashtable<_Key, std::pair, _Alloc,
+ __detail::_Select1st, std::equal_to<_Key>,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>;
+
+  bool
+  _M_equal(const __hashtable&) const;
+};
+
+  template
+bool
+_Equality<_Key, std::pair, _Alloc, __detail::_Select1st,
+	  std::equal_to<_Key>, _H1, _H2,
+	  _Hash, _RehashPolicy, _Traits, true>::
+_M_equal(const __hashtable& __other) const
+{
+  const __hashtable* __this = static_cast(this);
+
+  if (__this->size() != __other.size())
+	return false;
+
+  for (auto __itx = __this->begin(); __itx != __this->end(); ++__itx)
+	{
+	  const auto __ity = __other.find(__itx->first);
+	  if (__ity == __other.end() || !bool(__ity->second == __itx->second))
+	return false;
+	}
+  return true;
+}
+
+  /// Specialization.
+  template
+  struct _Equality<_Value, _Value, _Alloc, __detail::_Identity,
+		   std::equal_to<_Value>, _H1, _H2,
+		   _Hash, _RehashPolicy, _Traits, true>
+{
+  using __hashtable = _Hashtable<_Value, _Value, _Alloc,
+ __detail::_Identity, std::equal_to<_Value>,
+ _H1, _H2, _Hash, _RehashPolicy, _Traits>;
+
+  bool
+  _M_equal(const __hashtable&) const;
+};
+
+  template
+bool
+_Equality<_Value, _Value, _Alloc, __detail::_Identity,
+	  std::equal_to<_Value>, _H1, _H2,
+	  _Hash, _RehashPolicy, _Traits, true>::
+_M_equal(const __hashtable& __other) const
+{
+  const __hashtable* __this = static_cast(this);
+
+  if (__this->size() != __other.size())
+	return false;
+
+  for (auto __itx = __this->begin(); __itx != __this->end(); ++__itx)
+	if (__other.find(*__itx) == __other.end())
+	  return false;
+
+  return true;
+}
+
+  /// Specialization.
+  template
+struct _Equality<_Key, std::pair, _Alloc,
+		 __detail::_Select1st, 

[PATCH] libstdc++/92124 for associative containers

2020-01-03 Thread François Dumont

This is the patch to extend PR 92124 to the associative containers.

As it is pretty simple I thought it could maybe go in now.

I also think that the existing 92124 tests are not really testing what 
they should with the move assignment operators noexcept qualified, no ?


    PR libstdc++/92124
    * include/bits/stl_tree.h
    (_Rb_tree<>::_M_move_assign(_Rb_tree&, false_type)): Replace
    std::move_if_noexcept by std::move.
    * testsuite/23_containers/deque/92124.cc
    (X::operator==(X&&)): Qualify noexcept(false).
    * testsuite/23_containers/forward_list/92124.cc: Likewise.
    * testsuite/23_containers/list/92124.cc: Likewise.
    * testsuite/23_containers/vector/92124.cc: Likewise.
    * testsuite/23_containers/map/92124.cc: New.
    * testsuite/23_containers/set/92124.cc: New.

Tested under linux x86_64.

François

diff --git a/libstdc++-v3/include/bits/stl_tree.h b/libstdc++-v3/include/bits/stl_tree.h
index 12ba3181dd9..9339011e872 100644
--- a/libstdc++-v3/include/bits/stl_tree.h
+++ b/libstdc++-v3/include/bits/stl_tree.h
@@ -1695,7 +1695,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	[&__roan](const value_type& __cval)
 	{
 	  auto& __val = const_cast(__cval);
-	  return __roan(std::move_if_noexcept(__val));
+	  return __roan(std::move(__val));
 	};
 	  _M_root() = _M_copy(__x, __lbd);
 	  __x.clear();
diff --git a/libstdc++-v3/testsuite/23_containers/deque/92124.cc b/libstdc++-v3/testsuite/23_containers/deque/92124.cc
index 0bdfcb70dcf..ea16d415a49 100644
--- a/libstdc++-v3/testsuite/23_containers/deque/92124.cc
+++ b/libstdc++-v3/testsuite/23_containers/deque/92124.cc
@@ -30,7 +30,7 @@ struct X {
 // Tracking calls to assignment functions
 X& operator=(const X&) { throw 1; }
 
-X& operator=(X&&) noexcept(true) { return *this; }
+X& operator=(X&&) noexcept(false) { return *this; }
 };
 
 void
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/92124.cc b/libstdc++-v3/testsuite/23_containers/forward_list/92124.cc
index 3e1b7ab3421..4d037f3a08f 100644
--- a/libstdc++-v3/testsuite/23_containers/forward_list/92124.cc
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/92124.cc
@@ -30,7 +30,7 @@ struct X {
 // Tracking calls to assignment functions
 X& operator=(const X&) { throw 1; }
 
-X& operator=(X&&) noexcept(true) { return *this; }
+X& operator=(X&&) noexcept(false) { return *this; }
 };
 
 void
diff --git a/libstdc++-v3/testsuite/23_containers/list/92124.cc b/libstdc++-v3/testsuite/23_containers/list/92124.cc
index f9f2ed2e76f..49b74cab7e5 100644
--- a/libstdc++-v3/testsuite/23_containers/list/92124.cc
+++ b/libstdc++-v3/testsuite/23_containers/list/92124.cc
@@ -30,7 +30,7 @@ struct X {
 // Tracking calls to assignment functions
 X& operator=(const X&) { throw 1; }
 
-X& operator=(X&&) noexcept(true) { return *this; }
+X& operator=(X&&) noexcept(false) { return *this; }
 };
 
 void
diff --git a/libstdc++-v3/testsuite/23_containers/map/92124.cc b/libstdc++-v3/testsuite/23_containers/map/92124.cc
new file mode 100644
index 000..177c9d7abe9
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/map/92124.cc
@@ -0,0 +1,58 @@
+// Copyright (C) 2020 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
+// .
+
+// { dg-do run { target c++11 } }
+
+#include 
+#include 
+
+struct X
+{
+  X() = default;
+  X(const X&)
+  { if (Throw) throw 1; }
+
+  // Move constructor might throw
+  X(X&&) noexcept(false) {}
+
+  // Tracking calls to assignment functions
+  X& operator=(const X&) { throw 1; }
+
+  X& operator=(X&&) noexcept(false) { return *this; }
+
+  static bool Throw;
+};
+
+bool X::Throw = false;
+
+void
+test01()
+{
+  using A = __gnu_test::propagating_allocator, false>;
+  A a1(1), a2(2);
+  std::map, A>
+m1({ { 1, X() } }, a1),
+m2({ { 2, X() } }, a2);
+  X::Throw = true;
+  m1 = std::move(m2);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/set/92124.cc b/libstdc++-v3/testsuite/23_containers/set/92124.cc
new file mode 100644
index 000..95a2e9ce518
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/set/92124.cc
@@ -0,0 +1,73 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// 

Re: [PATCH] PR libstdc++/92124 on hashtable

2020-01-07 Thread François Dumont

On 1/6/20 4:17 PM, Jonathan Wakely wrote:

On 07/11/19 20:28 +0100, François Dumont wrote:
From what I understood from recent fix the unordered containers need 
to be updated the same way.


I hope you'll appreciate the usage of rvalue forwarding. Containers 


Yes, I think it makes sense.

node values are moved as soon as _M_assign is called with a rvalue 
reference to the source container.


Additionnaly this patch removes usages of lambdas in _Hashtable.

If you confirm it I'll check for the same on _Rb_tree.

    * include/bits/hashtable.h (_Hashtable<>::__alloc_node_gen_t): New
    template alias.
    (_Hashtable<>::__mv_if_value_type_mv_noexcept): New.
    (_Hashtable<>::__fwd_value): New.
    (_Hashtable<>::_M_assign_elements<>): Remove _NodeGenerator template
    parameter.
    (_Hashtable<>::_M_assign<>): Add _Ht template parameter.
    (_Hashtable<>::operator=(const _Hashtable<>&)): Adapt.
    (_Hashtable<>::_M_move_assign): 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_set/92124.cc: New.

Tested under Linux x86_64.

Ok to commit ?

François



diff --git a/libstdc++-v3/include/bits/hashtable.h 
b/libstdc++-v3/include/bits/hashtable.h

index ab579a7059e..c2b2219d471 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -255,6 +255,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION

  using __reuse_or_alloc_node_gen_t =
__detail::_ReuseOrAllocNode<__node_alloc_type>;
+  using __alloc_node_gen_t =
+    __detail::_AllocNode<__node_alloc_type>;

  // Simple RAII type for managing a node containing an element
  struct _Scoped_node
@@ -280,6 +282,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__node_type* _M_node;
  };

+  template
+    static constexpr
+    typename conditional<__move_if_noexcept_cond::value,
+ const _Tp&, _Tp&&>::type
+    __mv_if_value_type_mv_noexcept(_Tp& __x) noexcept
+    { return std::move(__x); }


This is only used in one place. Adding a function doesn't seem
worthwhile, you can just do this where you use it:

  using _Fwd_Ht = typename
conditional<__move_if_noexcept_cond::value,
    const _Ht&, _Ht>::type;
  _M_assign(std::forward<_Fwd_Ht>(__ht), __alloc_gen);



+  template
+    static constexpr
+    typename conditional::value,
+ value_type&&, const value_type&>::type


I think I'd prefer to reverse the condition, i.e.

  typename conditional::value,
   const value_type&, value_type&&>::type


+    __fwd_value(_Ht&&, value_type& __val) noexcept
+    { return std::move(__val); }


Since this doesn't use the first parameter, it can just be removed:

  template
    static constexpr
    typename conditional::value,
 const value_type&, value_type&&>::type
    __fwd_value(value_type& __val) noexcept
    { return std::move(__val); }

That simplifies the usage from:

  __fwd_value(std::forward<_Ht>(__ht), __ht_n->_M_v()))

so it becomes:

  __fwd_value<_Ht>(__ht_n->_M_v()))


Maybe __fwd_value<_Ht> should be __fwd_value_for<_Ht> so it's clear
how it depends on _Ht (because otherwise it looks like it is
forwarding as _Ht&& like std::forward<_Ht> would).

What do you think?


The simpler the better. So here is the cleaned patch.

Regarding the comment, I also rewrite it a little cause copy/move of 
elements doesn't depend on _NodeGenerator anymore.


    PR libstdc++/92124
    * include/bits/hashtable.h (_Hashtable<>::__alloc_node_gen_t): New
    template alias.
    (_Hashtable<>::__fwd_value_for): New.
    (_Hashtable<>::_M_assign_elements<>): Remove _NodeGenerator template
    parameter.
    (_Hashtable<>::_M_assign<>): Add _Ht template parameter.
    (_Hashtable<>::operator=(const _Hashtable<>&)): Adapt.
    (_Hashtable<>::_M_move_assign): 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_set/92124.cc: New.

Tested under Linux x86_64.

Ok to commit ?

François


diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 06b3cca6437..48eaa7600f3 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -255,6 +255,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   using

Re: Bind to std::equal plumbing in ranges::equal

2020-03-09 Thread François Dumont

On 3/6/20 11:12 AM, Jonathan Wakely wrote:

On 06/03/20 10:09 +, Jonathan Wakely wrote:

On 06/03/20 07:06 +0100, François Dumont wrote:
I started to work on ranges::equal to find out if what I am trying 
to do is totally silly.


With this patch ranges::equal is in pare with std::equal 
specializations that is to say that it correctly deals with Debug 
mode or std::deque iterators.


Once below patch is in:

https://gcc.gnu.org/ml/libstdc++/2019-12/msg00032.html

We will even be able to call std::__equal_aux1 directly using 
__niter_base to get rid of the Debug safe iterator layer. And even 
in this case get rid of the branch __use_memcmp and leave it to 
__equal_aux1.


I mainly fear the usage of std::iterator_traits in __equal_aux1 to 
be a problem. Is it in this context of sized_sentinel ?


I don't understand the question. No sentinel of type _Sent1 or _Sent2
gets passed to __equal_aux1 with your patch, you only pass iterators.


I just thought that std::iterator_traits was becoming somehow obsolete 
is the more recent Standard and that it was the reason for not using 
existing std algos.





But I think the patch is wrong:


+  return !std::__memcmp(__first1, __first2, __d1);
+    else
+  return std::__equal_aux(__first1, __first1 + __d1, 
__first2);


This last line will only compile if _Iter1 is random access, but all
we know at this point is that _Sent1 is a sized sentinel for _Iter1.
That doesn't mean it's necessarily random access.


Please try the example at https://wg21.link/counted.iterator#2 which
uses counted_iterator::iterator> and default_sentinel.
The sized_sentinel_for concept is satisfied, but you can't do first1+d1.


Thanks for this example, now I know what has to be supported. I'll see 
if I can find a solution before you do.


François



Re: [PATCH] Fix coroutine tests for libstdc++ gnu-version-namespace mode

2023-10-11 Thread François Dumont

Hi Iain

On 11/10/2023 09:30, Iain Sandoe wrote:

Hi François,


On 11 Oct 2023, at 05:49, François Dumont  wrote:
On 08/10/2023 15:59, Iain Sandoe wrote:

On 23 Sep 2023, at 21:10, François Dumont  wrote:

I'm eventually fixing those tests the same way we manage this problem in 
libstdc++ testsuite.

testsuite: Add optional libstdc++ version namespace in expected diagnostic

 When libstdc++ is build with --enable-symvers=gnu-versioned-namespace 
diagnostics are
 showing this namespace, currently __8.

 gcc/testsuite/ChangeLog:

 * testsuite/g++.dg/coroutines/coro-bad-alloc-00-bad-op-new.C: Add 
optional
 '__8' version namespace in expected diagnostic.
 * testsuite/g++.dg/coroutines/coro-bad-alloc-01-bad-op-del.C: 
Likewise.
 * testsuite/g++.dg/coroutines/coro-bad-alloc-02-no-op-new-nt.C: 
Likewise.
 * 
testsuite/g++.dg/coroutines/coro-bad-grooaf-01-grooaf-expected.C: Likewise.
 * testsuite/g++.dg/coroutines/pr97438.C: Likewise.
 * testsuite/g++.dg/coroutines/ramp-return-b.C: Likewise.

Tested under Linux x86_64.

I'm contributing to libstdc++ so I already have write access.

Ok to commit ?

As author of the tests, this LGTM as a suitable fix for now (at least, once the 
main
patch to fix versioned namespaces lands).

I just realized it was a "go", no ? Then why after the main patch ?

The "main patch" do not fix the versioned namespace. It just makes it adopt the 
cxx11 abi.

This patch fixes a problem that is as old as the tests and that is totally 
unrelated with the main one. I just wanted to improve the situation so that 
versioned namespace mode do not look more buggy than necessary when someone 
(like you) run those.

Maybe a misunderstanding on my part.  I was under the impression that 
versioned-namespace was currently unusable because it forces the old string 
ABI.  If that is not the case, then I guess the changes are OK now.


Said this way it sure makes this mode usability quite limited.

It's only functional to (almost) pass make check-c++ :-)



I am pretty concerned about the maintainability of this tho, hence this …


However, IMO, this could become quite painful as more g++ tests make use of std 
headers
(which is not really optional for facilities like this that are tightly-coupled 
between the FE and
the library).

For the future, it does seem that a more complete solution might be to 
introduce a
testsuite-wide definition for the C++ versioned std:: introducer, so that we 
can update it in one
place as the version changes.

So (as a thought experiment):
  - we’d have something of the form “CXX_STD” as a tcl global
  - we’d add the presence/absence of versioning to the relevant site.exp (which
means recognising the versioning choice also in the GCC configure)
  - we’d migrate tests to using ${CXX_STD} instead of "std::__N”  in matches

… I guess an alternative could be to cook up some alternate warning/error/etc
match functions that cater for arbitrary inline namespaces but that seems 
like a much
more tricky and invasive testsuite change.

thoughts?

I considered amending gcc/testsuite/lib/prune.exp to simply remove the version 
from the diagnostic. But the reply on why it was not working scared me, so this 
patch.

https://gcc.gnu.org/pipermail/gcc/2023-September/242526.html

Ah, I didn’t see that mail - will try to take a look at the weekend.


Ok, I'll instead chase for the patches on libstdc++ side then.

Moreover adopting cxx11 abi in versioned-namespace mode will imply a 
version bump which would force to patch those files again if we do not 
find another approach before.


Thanks,

François




[PATCH][_Hashtable] Use RAII to restore Rehash state

2023-10-25 Thread François Dumont

    libstdc++: [_Hashtable] Use RAII type to manage rehash functor state

    Replace usage of __try/__catch with a RAII type to restore rehash 
functor

    state when needed.

    libstdc++-v3/ChangeLog:

    * include/bits/hashtable_policy.h (_RehashStateGuard): New.
    (_Insert_base<>::_M_insert_range(_IIt, _IIt, const 
_NodeGet&, false_type)):

    Adapt.
    * include/bits/hashtable.h (__rehash_guard_t): New.
    (__rehash_state): Remove.
    (_M_rehash): Remove.
    (_M_rehash_aux): Rename into _M_rehash.
    (_M_assign_elements, _M_insert_unique_node, 
_M_insert_multi_node): Adapt.

    (rehash): Adapt.


Tested under Linux x64.

Ok to commit ?

François
diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 0857448f7ed..64071ac1fb2 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -234,6 +234,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  _RehashPolicy, _Traits>;
   using __enable_default_ctor
 	= _Hashtable_enable_default_ctor<_Equal, _Hash, _Alloc>;
+  using __rehash_guard_t
+	= __detail::_RehashStateGuard<_RehashPolicy>;
 
 public:
   typedef _Key		key_type;
@@ -264,7 +266,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 private:
   using __rehash_type = _RehashPolicy;
-  using __rehash_state = typename __rehash_type::_State;
 
   using __unique_keys = typename __traits_type::__unique_keys;
 
@@ -1200,14 +1201,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 private:
   // Helper rehash method used when keys are unique.
-  void _M_rehash_aux(size_type __bkt_count, true_type __uks);
+  void _M_rehash(size_type __bkt_count, true_type __uks);
 
   // Helper rehash method used when keys can be non-unique.
-  void _M_rehash_aux(size_type __bkt_count, false_type __uks);
-
-  // Unconditionally change size of bucket array to n, restore
-  // hash policy state to __state on exception.
-  void _M_rehash(size_type __bkt_count, const __rehash_state& __state);
+  void _M_rehash(size_type __bkt_count, false_type __uks);
 };
 
   // Definitions of class template _Hashtable's out-of-line member functions.
@@ -1337,7 +1334,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   {
 	__buckets_ptr __former_buckets = nullptr;
 	std::size_t __former_bucket_count = _M_bucket_count;
-	const __rehash_state& __former_state = _M_rehash_policy._M_state();
+	__rehash_guard_t __rehash_guard(_M_rehash_policy);
 
 	if (_M_bucket_count != __ht._M_bucket_count)
 	  {
@@ -1359,6 +1356,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_M_assign(std::forward<_Ht>(__ht), __roan);
 	if (__former_buckets)
 	  _M_deallocate_buckets(__former_buckets, __former_bucket_count);
+	__rehash_guard._M_reset = false;
 	  }
 	__catch(...)
 	  {
@@ -1366,7 +1364,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  {
 		// Restore previous buckets.
 		_M_deallocate_buckets();
-		_M_rehash_policy._M_reset(__former_state);
 		_M_buckets = __former_buckets;
 		_M_bucket_count = __former_bucket_count;
 	  }
@@ -2142,17 +2139,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			  __node_ptr __node, size_type __n_elt)
 -> iterator
 {
-  const __rehash_state& __saved_state = _M_rehash_policy._M_state();
+  __rehash_guard_t __rehash_guard(_M_rehash_policy);
   std::pair __do_rehash
 	= _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count,
 	  __n_elt);
 
   if (__do_rehash.first)
 	{
-	  _M_rehash(__do_rehash.second, __saved_state);
+	  _M_rehash(__do_rehash.second, true_type{});
 	  __bkt = _M_bucket_index(__code);
 	}
 
+  __rehash_guard._M_reset = false;
   this->_M_store_code(*__node, __code);
 
   // Always insert at the beginning of the bucket.
@@ -2172,13 +2170,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			 __hash_code __code, __node_ptr __node)
 -> iterator
 {
-  const __rehash_state& __saved_state = _M_rehash_policy._M_state();
+  __rehash_guard_t __rehash_guard(_M_rehash_policy);
   std::pair __do_rehash
 	= _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1);
 
   if (__do_rehash.first)
-	_M_rehash(__do_rehash.second, __saved_state);
+	_M_rehash(__do_rehash.second, false_type{});
 
+  __rehash_guard._M_reset = false;
   this->_M_store_code(*__node, __code);
   const key_type& __k = _ExtractKey{}(__node->_M_v());
   size_type __bkt = _M_bucket_index(__code);
@@ -2509,39 +2508,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	   _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
 rehash(size_type __bkt_count)
 {
-  const __rehash_state& __saved_state = _M_rehash_policy._M_state();
+  __rehash_guard_t __rehash_guard(_M_rehash_policy);
   __bkt_count
 	= std::max(_M_rehash_policy._M_bkt_for_elements(_M_element_count + 1),
 		   __bkt_count);
   __bkt_count = _M_rehash_policy._M_next_bkt(__bkt_count);
 
  

[committed][_GLIBCXX_INLINE_VERSION] Fix constract violation

2023-10-29 Thread François Dumont

This fixes handle_contract_violation under versioned namespace mode.

Tested under Linux x64 and confirmed to also fix Darwin build.

libstdc++: [_GLIBCXX_INLINE_VERSION] Provide handle_contract_violation 
symbol


libstdc++-v3/ChangeLog:

    * src/experimental/contract.cc
    [_GLIBCXX_INLINE_VERSION](handle_contract_violation): Provide 
symbol

    without version namespace decoration for gcc.

François
diff --git a/libstdc++-v3/src/experimental/contract.cc b/libstdc++-v3/src/experimental/contract.cc
index 504a6c041f1..d550b49c4eb 100644
--- a/libstdc++-v3/src/experimental/contract.cc
+++ b/libstdc++-v3/src/experimental/contract.cc
@@ -67,3 +67,11 @@ handle_contract_violation (const std::experimental::contract_violation 
   std::cerr << std::endl;
 #endif
 }
+
+#if _GLIBCXX_INLINE_VERSION
+// Provide symbol without version namespace decoration for gcc.
+extern "C" __attribute__ ((weak)) void
+_Z25handle_contract_violationRKNSt12experimental18contract_violationE
+(const std::experimental::contract_violation )
+{ handle_contract_violation(violation); }
+#endif


[committed][_GLIBCXX_INLINE_VERSION] Add emul TLS symbol exports

2023-10-29 Thread François Dumont

libstdc++: [_GLIBCXX_INLINE_VERSION] Add emul TLS symbols

libstdc++-v3/ChangeLog:

    * config/abi/pre/gnu-versioned-namespace.ver: Add missing emul TLS
    symbols.

François
diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
index 9fab8bead15..3140a9628d8 100644
--- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
+++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
@@ -78,6 +78,8 @@ GLIBCXX_8.0 {
 
 # thread/mutex/condition_variable/future
 __once_proxy;
+__emutls_v._ZSt3__811__once_call;
+__emutls_v._ZSt3__815__once_callable;
 
 # std::__convert_to_v
 _ZNSt3__814__convert_to_v*;


[PATCH][_Hashtable] Add missing destructor call

2023-11-06 Thread François Dumont
Noticed looking for other occasion to replace __try/__catch with RAII 
helper.


    libstdc++: [_Hashtable] Add missing node destructor call

    libstdc++-v3/ChangeLog:

    * include/bits/hashtable_policy.h
    (_Hashtable_alloc<>::_M_allocate_node): Add missing call to 
node destructor

    on construct exception.

Tested under Linux x64, ok to commit ?

I hope gmail appli will appreciate .diff instead of .patch. .txt are not 
in .gitignore so annoying to use for patches.


François
diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h
index 2d13bda6ae0..ed2b2c02a4a 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -2020,19 +2020,20 @@ namespace __detail
   _Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&&... __args)
   -> __node_ptr
   {
-	auto __nptr = __node_alloc_traits::allocate(_M_node_allocator(), 1);
+	auto& __alloc = _M_node_allocator();
+	auto __nptr = __node_alloc_traits::allocate(__alloc, 1);
 	__node_ptr __n = std::__to_address(__nptr);
 	__try
 	  {
 	::new ((void*)__n) __node_type;
-	__node_alloc_traits::construct(_M_node_allocator(),
-	   __n->_M_valptr(),
+	__node_alloc_traits::construct(__alloc, __n->_M_valptr(),
 	   std::forward<_Args>(__args)...);
 	return __n;
 	  }
 	__catch(...)
 	  {
-	__node_alloc_traits::deallocate(_M_node_allocator(), __nptr, 1);
+	__n->~__node_type();
+	__node_alloc_traits::deallocate(__alloc, __nptr, 1);
 	__throw_exception_again;
 	  }
   }


Re: [PATCH][_Hashtable] Use RAII to restore Rehash state

2023-10-26 Thread François Dumont


On 26/10/2023 12:43, Jonathan Wakely wrote:

On 26/10/23 07:18 +0200, François Dumont wrote:

    libstdc++: [_Hashtable] Use RAII type to manage rehash functor state

    Replace usage of __try/__catch with a RAII type to restore rehash 
functor

    state when needed.


Generally I really like replacing try-catch with RAII but I have some
questions below.


    libstdc++-v3/ChangeLog:

    * include/bits/hashtable_policy.h (_RehashStateGuard): New.
    (_Insert_base<>::_M_insert_range(_IIt, _IIt, const 
_NodeGet&, false_type)):

    Adapt.
    * include/bits/hashtable.h (__rehash_guard_t): New.
    (__rehash_state): Remove.
    (_M_rehash): Remove.
    (_M_rehash_aux): Rename into _M_rehash.
    (_M_assign_elements, _M_insert_unique_node, 
_M_insert_multi_node): Adapt.

    (rehash): Adapt.


Tested under Linux x64.

Ok to commit ?

François


diff --git a/libstdc++-v3/include/bits/hashtable.h 
b/libstdc++-v3/include/bits/hashtable.h

index 0857448f7ed..64071ac1fb2 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -234,6 +234,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  _RehashPolicy, _Traits>;
  using __enable_default_ctor
= _Hashtable_enable_default_ctor<_Equal, _Hash, _Alloc>;
+  using __rehash_guard_t
+    = __detail::_RehashStateGuard<_RehashPolicy>;

    public:
  typedef _Key    key_type;
@@ -264,7 +266,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION

    private:
  using __rehash_type = _RehashPolicy;
-  using __rehash_state = typename __rehash_type::_State;

  using __unique_keys = typename __traits_type::__unique_keys;

@@ -1200,14 +1201,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION

    private:
  // Helper rehash method used when keys are unique.
-  void _M_rehash_aux(size_type __bkt_count, true_type __uks);
+  void _M_rehash(size_type __bkt_count, true_type __uks);

  // Helper rehash method used when keys can be non-unique.
-  void _M_rehash_aux(size_type __bkt_count, false_type __uks);
-
-  // Unconditionally change size of bucket array to n, restore
-  // hash policy state to __state on exception.
-  void _M_rehash(size_type __bkt_count, const __rehash_state& 
__state);

+  void _M_rehash(size_type __bkt_count, false_type __uks);
    };

  // Definitions of class template _Hashtable's out-of-line member 
functions.

@@ -1337,7 +1334,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  {
__buckets_ptr __former_buckets = nullptr;
std::size_t __former_bucket_count = _M_bucket_count;
-    const __rehash_state& __former_state = _M_rehash_policy._M_state();
+    __rehash_guard_t __rehash_guard(_M_rehash_policy);

if (_M_bucket_count != __ht._M_bucket_count)
  {
@@ -1359,6 +1356,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    _M_assign(std::forward<_Ht>(__ht), __roan);
    if (__former_buckets)
  _M_deallocate_buckets(__former_buckets, 
__former_bucket_count);

+    __rehash_guard._M_reset = false;


I find this confusing. Usually "reset" means that something is
cleared, so won't take an action in the destructor. e.g. if you use
std::unique_ptr::reset() then the object is destroyed immediately, and
then nothing happens in the destructor. Here it's the opposite,
_M_reset=true means that it _sould_ do something in the destructor.

The problem is the ambiguity between "reset the state in the
destructor later" and "reset the object to an empty state now".

If the member was called _M_guarded then it might be clearer.
_M_guarded=true means the guard is active, and will restore the state
later. Or _M_active, or _M_armed, or even _M_reset_in_dtor. Any of
those names avoids the confusion with the semantics of
std::unique_ptr::reset() and similar well-known APIs.

Or what I usually do is store a pointer to the guarded object in the
RAII guard type, and then just null the pointer to disarm the guard.
That means you don't need a separate bool member variable. If
_RehashStateGuard::_M_rehash_policy was called _M_guarded_obj and was
a _RehashPolicy* instead of _RehashPolicy& then disarming it would be:

   __rehash_guard._M_guarded_obj = nullptr;

This seems clear to me, as it says that the guard no longer has
anything to guard, so won't do anything in the destructor.


Looks clearer to me too.

I started with a _RehashStateScope and a _M_commit() method, it could 
have been worst :-)






  }
__catch(...)
  {
@@ -1366,7 +1364,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  {
    // Restore previous buckets.
    _M_deallocate_buckets();
-    _M_rehash_policy._M_reset(__former_state);
    _M_buckets = __former_buckets;
    _M_bucket_count = __former_bucket_count;
  }
@@ -2142,17 +2139,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  __node_ptr __node, size_type 

Re: [committed][_GLIBCXX_INLINE_VERSION] Add emul TLS symbol exports

2023-10-30 Thread François Dumont



On 30/10/2023 14:58, Jonathan Wakely wrote:

On Sun, 29 Oct 2023 at 21:25, François Dumont  wrote:

libstdc++: [_GLIBCXX_INLINE_VERSION] Add emul TLS symbols

libstdc++-v3/ChangeLog:

  * config/abi/pre/gnu-versioned-namespace.ver: Add missing emul TLS
  symbols.


Please put a comment above the two new lines, the same as in gnu.ver:

# targets using emutls

OK with that change, thanks.


It's already committed as it was a trivial change limited to the 
versioned namespace special mode for which I'm maintainer.


Can you confirm you want a new commit just to add this comment ?




Re: [committed][_GLIBCXX_INLINE_VERSION] Fix constract violation

2023-10-30 Thread François Dumont



On 30/10/2023 14:45, Jonathan Wakely wrote:

On Sun, 29 Oct 2023 at 21:11, François Dumont  wrote:

This fixes handle_contract_violation under versioned namespace mode.

Tested under Linux x64 and confirmed to also fix Darwin build.

libstdc++: [_GLIBCXX_INLINE_VERSION] Provide handle_contract_violation
symbol

libstdc++-v3/ChangeLog:

  * src/experimental/contract.cc
  [_GLIBCXX_INLINE_VERSION](handle_contract_violation): Provide
symbol
  without version namespace decoration for gcc.
+#if _GLIBCXX_INLINE_VERSION
+// Provide symbol without version namespace decoration for gcc.

For the comment in the code, I think this would be better:

// The compiler expects the contract_violation class to be in an unversioned
// namespace, so provide a forwarding function with the expected symbol name.

Sure, I'll update it.

Do we want the forwarding function to be a weak symbol? The main
handler function is weak because we want users to be able to override
it with their own handler. But for this new forwarding function, they
can't even declare it (because it has a reserved name that doesn't
demangle to a valid type for the versioned namespace build).


Good point, I see no reason neither so I'll remove it.



[PATCH][_Hashtable] Fix merge

2023-10-18 Thread François Dumont

libstdc++: [_Hashtable] Do not reuse untrusted cached hash code

On merge reuse merged node cached hash code only if we are on the same 
type of
hash and this hash is stateless. Usage of function pointers or 
std::function as

hash functor will prevent this optimization.

libstdc++-v3/ChangeLog

    * include/bits/hashtable_policy.h
    (_Hash_code_base::_M_hash_code(const _Hash&, const 
_Hash_node_value<>&)): Remove.
    (_Hash_code_base::_M_hash_code<_H2>(const _H2&, const 
_Hash_node_value<>&)): Remove.

    * include/bits/hashtable.h
    (_M_src_hash_code<_H2>(const _H2&, const key_type&, const 
__node_value_type&)): New.

    (_M_merge_unique<>, _M_merge_multi<>): Use latter.
    * testsuite/23_containers/unordered_map/modifiers/merge.cc
    (test04, test05, test06): New test cases.

Tested under Linux x86_64, ok to commit ?

François

diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 4c12dc895b2..f69acfe5213 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -1109,6 +1109,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return { __n, this->_M_node_allocator() };
   }
 
+  // Check and if needed compute hash code using _Hash as __n _M_hash_code,
+  // if present, was computed using _H2.
+  template
+	__hash_code
+	_M_src_hash_code(const _H2&, const key_type& __k,
+			 const __node_value_type& __src_n) const
+	{
+	  if constexpr (std::is_same_v<_H2, _Hash>)
+	if constexpr (std::is_empty_v<_Hash>)
+	  return this->_M_hash_code(__src_n);
+
+	  return this->_M_hash_code(__k);
+	}
+
 public:
   // Extract a node.
   node_type
@@ -1146,7 +1160,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  auto __pos = __i++;
 	  const key_type& __k = _ExtractKey{}(*__pos);
 	  __hash_code __code
-		= this->_M_hash_code(__src.hash_function(), *__pos._M_cur);
+		= _M_src_hash_code(__src.hash_function(), __k, *__pos._M_cur);
 	  size_type __bkt = _M_bucket_index(__code);
 	  if (_M_find_node(__bkt, __k, __code) == nullptr)
 		{
@@ -1174,8 +1188,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  for (auto __i = __src.cbegin(), __end = __src.cend(); __i != __end;)
 	{
 	  auto __pos = __i++;
+	  const key_type& __k = _ExtractKey{}(*__pos);
 	  __hash_code __code
-		= this->_M_hash_code(__src.hash_function(), *__pos._M_cur);
+		= _M_src_hash_code(__src.hash_function(), __k, *__pos._M_cur);
 	  auto __nh = __src.extract(__pos);
 	  __hint = _M_insert_multi_node(__hint, __code, __nh._M_ptr)._M_cur;
 	  __nh._M_ptr = nullptr;
diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h
index 86b32fb15f2..5d162463dc3 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -1319,19 +1319,6 @@ namespace __detail
 	  return _M_hash()(__k);
 	}
 
-  __hash_code
-  _M_hash_code(const _Hash&,
-		   const _Hash_node_value<_Value, true>& __n) const
-  { return __n._M_hash_code; }
-
-  // Compute hash code using _Hash as __n _M_hash_code, if present, was
-  // computed using _H2.
-  template
-	__hash_code
-	_M_hash_code(const _H2&,
-		const _Hash_node_value<_Value, __cache_hash_code>& __n) const
-	{ return _M_hash_code(_ExtractKey{}(__n._M_v())); }
-
   __hash_code
   _M_hash_code(const _Hash_node_value<_Value, false>& __n) const
   { return _M_hash_code(_ExtractKey{}(__n._M_v())); }
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/merge.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/merge.cc
index b140ce452aa..c051b58137a 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/merge.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/merge.cc
@@ -17,15 +17,29 @@
 
 // { dg-do run { target c++17 } }
 
+#include 
+#include 
 #include 
 #include 
 #include 
 
 using test_type = std::unordered_map;
 
-struct hash {
-  auto operator()(int i) const noexcept { return ~std::hash()(i); }
-};
+template
+  struct xhash
+  {
+auto operator()(const T& i) const noexcept
+{ return ~std::hash()(i); }
+  };
+
+
+namespace std
+{
+  template
+struct __is_fast_hash> : __is_fast_hash>
+{ };
+}
+
 struct equal : std::equal_to<> { };
 
 template
@@ -64,7 +78,7 @@ test02()
 {
   const test_type c0{ {1, 10}, {2, 20}, {3, 30} };
   test_type c1 = c0;
-  std::unordered_map c2( c0.begin(), c0.end() );
+  std::unordered_map, equal> c2( c0.begin(), c0.end() );
 
   c1.merge(c2);
   VERIFY( c1 == c0 );
@@ -89,7 +103,7 @@ test03()
 {
   const test_type c0{ {1, 10}, {2, 20}, {3, 30} };
   test_type c1 = c0;
-  std::unordered_multimap c2( c0.begin(), c0.end() );
+  std::unordered_multimap, equal> c2( c0.begin(), c0.end() );
   c1.merge(c2);
   VERIFY( c1 == c0 );
   VERIFY( equal_elements(c2, c0) );
@@ -125,10 +139,164 @@ test03()
   VERIFY( c2.empty() );
 }
 
+void
+test04()
+{
+  const 

[PATCH] Fix coroutine tests for libstdc++ gnu-version-namespace mode

2023-09-23 Thread François Dumont
I'm eventually fixing those tests the same way we manage this problem in 
libstdc++ testsuite.


   testsuite: Add optional libstdc++ version namespace in expected 
diagnostic


    When libstdc++ is build with 
--enable-symvers=gnu-versioned-namespace diagnostics are

    showing this namespace, currently __8.

    gcc/testsuite/ChangeLog:

    * 
testsuite/g++.dg/coroutines/coro-bad-alloc-00-bad-op-new.C: Add optional

    '__8' version namespace in expected diagnostic.
    * 
testsuite/g++.dg/coroutines/coro-bad-alloc-01-bad-op-del.C: Likewise.
    * 
testsuite/g++.dg/coroutines/coro-bad-alloc-02-no-op-new-nt.C: Likewise.
    * 
testsuite/g++.dg/coroutines/coro-bad-grooaf-01-grooaf-expected.C: Likewise.

    * testsuite/g++.dg/coroutines/pr97438.C: Likewise.
    * testsuite/g++.dg/coroutines/ramp-return-b.C: Likewise.

Tested under Linux x86_64.

I'm contributing to libstdc++ so I already have write access.

Ok to commit ?

François
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 73e7f381020..c44b71a04cb 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -4867,7 +4867,7 @@ dnl
 dnl Control whether the library should define symbols for old and new ABIs.
 dnl This affects definitions of strings, stringstreams and locale facets.
 dnl
-dnl --disable-libstdcxx-dual-abi will use old ABI for all types.
+dnl --disable-libstdcxx-dual-abi will use new ABI for all types.
 dnl
 dnl Defines:
 dnl  _GLIBCXX_USE_DUAL_ABI (always defined, either to 1 or 0)
@@ -4883,7 +4883,7 @@ AC_DEFUN([GLIBCXX_ENABLE_LIBSTDCXX_DUAL_ABI], [
   else
 if test x"$enable_libstdcxx_dual_abi" != xyes; then
   AC_MSG_NOTICE([dual ABI is disabled])
-  default_libstdcxx_abi="gcc4-compatible"
+  default_libstdcxx_abi="new"
 fi
   fi
   GLIBCXX_CONDITIONAL(ENABLE_DUAL_ABI, test $enable_libstdcxx_dual_abi = yes)
@@ -4898,7 +4898,6 @@ dnl Defines:
 dnl  _GLIBCXX_USE_CXX11_ABI (always defined, either to 1 or 0)
 dnl
 AC_DEFUN([GLIBCXX_DEFAULT_ABI], [
-  if test x$enable_libstdcxx_dual_abi = xyes; then
   AC_MSG_CHECKING([for default std::string ABI to use])
   AC_ARG_WITH([default-libstdcxx-abi],
 AS_HELP_STRING([--with-default-libstdcxx-abi],
@@ -4912,7 +4911,6 @@ AC_DEFUN([GLIBCXX_DEFAULT_ABI], [
  ],
 [default_libstdcxx_abi="new"])
   AC_MSG_RESULT(${default_libstdcxx_abi})
-  fi
   if test $default_libstdcxx_abi = "new"; then
 glibcxx_cxx11_abi=1
 glibcxx_cxx98_abi=0
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index 6e9a532a359..14f9569597a 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -70712,13 +70712,12 @@ $as_echo "$as_me: dual ABI is disabled" >&6;}
 if test x"$enable_libstdcxx_dual_abi" != xyes; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: dual ABI is disabled" >&5
 $as_echo "$as_me: dual ABI is disabled" >&6;}
-  default_libstdcxx_abi="gcc4-compatible"
+  default_libstdcxx_abi="new"
 fi
   fi
 
 
 
-  if test x$enable_libstdcxx_dual_abi = xyes; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for default std::string ABI to use" >&5
 $as_echo_n "checking for default std::string ABI to use... " >&6; }
 
@@ -70737,7 +70736,6 @@ fi
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${default_libstdcxx_abi}" >&5
 $as_echo "${default_libstdcxx_abi}" >&6; }
-  fi
   if test $default_libstdcxx_abi = "new"; then
 glibcxx_cxx11_abi=1
 glibcxx_cxx98_abi=0


[PATCH][_GLIBCXX_INLINE_VERSION] Fix

2023-09-19 Thread François Dumont

libstdc++: Remove std::constract_violation from versioned namespace

GCC expects this type to be in std namespace directly.

libstdc++-v3/ChangeLog:

    * include/experimental/contract:
    Remove _GLIBCXX_BEGIN_NAMESPACE_VERSION/_GLIBCXX_END_NAMESPACE_VERSION.

It does fix 29 g++.dg/contracts in gcc testsuite.

Ok to commit ?

François
diff --git a/libstdc++-v3/include/experimental/contract b/libstdc++-v3/include/experimental/contract
index fbf5ed01d8b..8bc12380cec 100644
--- a/libstdc++-v3/include/experimental/contract
+++ b/libstdc++-v3/include/experimental/contract
@@ -39,7 +39,6 @@
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 namespace experimental
 {
@@ -71,7 +70,6 @@ namespace experimental
 
 } // namespace experimental
 
-_GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 // To override the contract violation handler, define


Re: [PATCH] [11/12/13/14 Regression] ABI break in _Hash_node_value_base since GCC 11 [PR 111050]

2023-09-28 Thread François Dumont



On 28/09/2023 18:18, Jonathan Wakely wrote:

On Wed, 27 Sept 2023 at 05:44, François Dumont  wrote:

Still no chance to get feedback from TC ? Maybe I can commit the below
then ?

I've heard back from Tim now. Please use "Tim Song
" as the author.

You can change the commit again using git commit --amend --author "Tim
Song "


Sure :-)



OK for trunk with that change - thanks for waiting.


Committed to trunk, let me know for backports.


AFAICS on gcc mailing list several gcc releases were done recently, too
late.

There have been no releases this month, so the delay hasn't caused any problems.


I was confused by emails like this one:

https://gcc.gnu.org/pipermail/gcc/2023-September/242429.html

I just subscribed to gcc mailing list, I had no idea there were regular 
snapshots like this.




Re: [PATCH] Fix coroutine tests for libstdc++ gnu-version-namespace mode

2023-10-02 Thread François Dumont

Hi

Gentle reminder for this minor patch.

Thanks

On 23/09/2023 22:10, François Dumont wrote:
I'm eventually fixing those tests the same way we manage this problem 
in libstdc++ testsuite.


   testsuite: Add optional libstdc++ version namespace in expected 
diagnostic


    When libstdc++ is build with 
--enable-symvers=gnu-versioned-namespace diagnostics are

    showing this namespace, currently __8.

    gcc/testsuite/ChangeLog:

    * 
testsuite/g++.dg/coroutines/coro-bad-alloc-00-bad-op-new.C: Add optional

    '__8' version namespace in expected diagnostic.
    * 
testsuite/g++.dg/coroutines/coro-bad-alloc-01-bad-op-del.C: Likewise.
    * 
testsuite/g++.dg/coroutines/coro-bad-alloc-02-no-op-new-nt.C: Likewise.
    * 
testsuite/g++.dg/coroutines/coro-bad-grooaf-01-grooaf-expected.C: 
Likewise.

    * testsuite/g++.dg/coroutines/pr97438.C: Likewise.
    * testsuite/g++.dg/coroutines/ramp-return-b.C: Likewise.

Tested under Linux x86_64.

I'm contributing to libstdc++ so I already have write access.

Ok to commit ?

François


Re: [PATCH] [11/12/13/14 Regression] ABI break in _Hash_node_value_base since GCC 11 [PR 111050]

2023-10-02 Thread François Dumont

Now backport to gcc-11/12/13 branches.

On 29/09/2023 11:53, Jonathan Wakely wrote:

On Thu, 28 Sept 2023 at 18:25, François Dumont  wrote:


On 28/09/2023 18:18, Jonathan Wakely wrote:

On Wed, 27 Sept 2023 at 05:44, François Dumont  wrote:

Still no chance to get feedback from TC ? Maybe I can commit the below
then ?

I've heard back from Tim now. Please use "Tim Song
" as the author.

You can change the commit again using git commit --amend --author "Tim
Song "

Sure :-)


OK for trunk with that change - thanks for waiting.

Committed to trunk, let me know for backports.

Please wait a few days in case of problems on the trunk (although I
don't expect any) and then OK for 11/12/13 too - thanks!



AFAICS on gcc mailing list several gcc releases were done recently, too
late.

There have been no releases this month, so the delay hasn't caused any problems.

I was confused by emails like this one:

https://gcc.gnu.org/pipermail/gcc/2023-September/242429.html

I just subscribed to gcc mailing list, I had no idea there were regular
snapshots like this.



Re: [PATCH] [11/12/13/14 Regression] ABI break in _Hash_node_value_base since GCC 11 [PR 111050]

2023-09-26 Thread François Dumont
Still no chance to get feedback from TC ? Maybe I can commit the below 
then ?


AFAICS on gcc mailing list several gcc releases were done recently, too 
late.



On 14/09/2023 06:46, François Dumont wrote:

Author: TC 
Date:   Wed Sep 6 19:31:55 2023 +0200

    libstdc++: Force _Hash_node_value_base methods inline to fix abi 
(PR111050)


https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=1b6f0476837205932613ddb2b3429a55c26c409d 

    changed _Hash_node_value_base to no longer derive from 
_Hash_node_base, which means
    that its member functions expect _M_storage to be at a different 
offset. So explosions
    result if an out-of-line definition is emitted for any of the 
member functions (say,
    in a non-optimized build) and the resulting object file is then 
linked with code built

    using older version of GCC/libstdc++.

    libstdc++-v3/ChangeLog:

    PR libstdc++/111050
    * include/bits/hashtable_policy.h
    (_Hash_node_value_base<>::_M_valptr(), 
_Hash_node_value_base<>::_M_v())

    Add [[__gnu__::__always_inline__]].

Ok to commit ?

On 12/09/2023 18:09, Jonathan Wakely wrote:
On Mon, 11 Sept 2023 at 18:19, François Dumont  
wrote:


On 11/09/2023 13:51, Jonathan Wakely wrote:

On Sun, 10 Sept 2023 at 14:57, François Dumont via Libstdc++
 wrote:

Following confirmation of the fix by TC here is the patch where I'm
simply adding a 'constexpr' on _M_next().

Please let me know this ChangeLog entry is correct. I would prefer 
this
patch to be assigned to 'TC' with me as co-author but I don't know 
how
to do such a thing. Unless I need to change my user git identity 
to do so ?

Sam already explained that, but please check with Tim how he wants to
be credited, if at all. He doesn't have a copyright assignment, and
hasn't added a DCO sign-off to the patch, but it's small enough to not
need it as this is the first contribution credited to him.


   libstdc++: Add constexpr qualification to 
_Hash_node::_M_next()

What has this constexpr addition got to do with the ABI change and the
always_inline attributes?

It certainly doesn't seem like it should be the summary line of the
git commit message.
Oops, sorry, that's what I had started to do before Tim submitted 
anything.


Here is latest version:

No patch attached, and the ChangeLog below still mentions the constexpr.

I've pinged Tim via another channel to ask him about the author 
attribution.




Author: TC 
Date:   Wed Sep 6 19:31:55 2023 +0200

  libstdc++: Force inline on _Hash_node_value_base methods to 
fix abi

(PR111050)

https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=1b6f0476837205932613ddb2b3429a55c26c409d 


  changed _Hash_node_value_base to no longer derive from
_Hash_node_base, which means
  that its member functions expect _M_storage to be at a different
offset. So explosions
  result if an out-of-line definition is emitted for any of the
member functions (say,
  in a non-optimized build) and the resulting object file is then
linked with code built
  using older version of GCC/libstdc++.

  libstdc++-v3/ChangeLog:

  PR libstdc++/111050
  * include/bits/hashtable_policy.h
  (_Hash_node_value_base<>::_M_valptr(),
_Hash_node_value_base<>::_M_v())
  Add [[__gnu__::__always_inline__]].
  (_Hash_node<>::_M_next()): Add constexpr.

  Co-authored-by: François Dumont 

Ok for you TC (Tim ?) ?




Re: [PATCH] Fix coroutine tests for libstdc++ gnu-version-namespace mode

2023-10-03 Thread François Dumont

Indeed ! Here is the right one.

On 03/10/2023 11:52, Jonathan Wakely wrote:

On Mon, 2 Oct 2023 at 18:07, François Dumont  wrote:

Hi

Gentle reminder for this minor patch.

It looks like you attached the wrong patch.



Thanks

On 23/09/2023 22:10, François Dumont wrote:

I'm eventually fixing those tests the same way we manage this problem
in libstdc++ testsuite.

testsuite: Add optional libstdc++ version namespace in expected
diagnostic

 When libstdc++ is build with
--enable-symvers=gnu-versioned-namespace diagnostics are
 showing this namespace, currently __8.

 gcc/testsuite/ChangeLog:

 *
testsuite/g++.dg/coroutines/coro-bad-alloc-00-bad-op-new.C: Add optional
 '__8' version namespace in expected diagnostic.
 *
testsuite/g++.dg/coroutines/coro-bad-alloc-01-bad-op-del.C: Likewise.
 *
testsuite/g++.dg/coroutines/coro-bad-alloc-02-no-op-new-nt.C: Likewise.
 *
testsuite/g++.dg/coroutines/coro-bad-grooaf-01-grooaf-expected.C:
Likewise.
 * testsuite/g++.dg/coroutines/pr97438.C: Likewise.
 * testsuite/g++.dg/coroutines/ramp-return-b.C: Likewise.

Tested under Linux x86_64.

I'm contributing to libstdc++ so I already have write access.

Ok to commit ?

Françoisdiff --git a/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-00-bad-op-new.C b/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-00-bad-op-new.C
index 4706deebf4e..928e0c974e1 100644
--- a/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-00-bad-op-new.C
+++ b/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-00-bad-op-new.C
@@ -6,7 +6,7 @@
 #include "coro1-allocators.h"
 
 struct coro1
-f ()  /* { dg-error {'operator new' is provided by 'std::__n4861::__coroutine_traits_impl::promise_type' \{aka 'coro1::promise_type'\} but is not usable with the function signature 'coro1 f\(\)'} } */
+f ()  /* { dg-error {'operator new' is provided by 'std::(__8::)?__n4861::__coroutine_traits_impl::promise_type' \{aka 'coro1::promise_type'\} but is not usable with the function signature 'coro1 f\(\)'} } */
 {
   co_return;
 }
diff --git a/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-01-bad-op-del.C b/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-01-bad-op-del.C
index 252cb5e442c..6bed524aa0a 100644
--- a/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-01-bad-op-del.C
+++ b/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-01-bad-op-del.C
@@ -6,7 +6,7 @@
 #include "coro1-allocators.h"
 
 struct coro1
-f ()  /* { dg-error {'operator delete' is provided by 'std::__n4861::__coroutine_traits_impl::promise_type' \{aka 'coro1::promise_type'\} but is not usable with the function signature 'coro1 f\(\)'} } */
+f ()  /* { dg-error {'operator delete' is provided by 'std::(__8::)?__n4861::__coroutine_traits_impl::promise_type' \{aka 'coro1::promise_type'\} but is not usable with the function signature 'coro1 f\(\)'} } */
 {
   co_return;
 }
diff --git a/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-02-no-op-new-nt.C b/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-02-no-op-new-nt.C
index 89972b60945..0a545fed0e3 100644
--- a/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-02-no-op-new-nt.C
+++ b/gcc/testsuite/g++.dg/coroutines/coro-bad-alloc-02-no-op-new-nt.C
@@ -9,7 +9,7 @@
 #include "coro1-allocators.h"
 
 struct coro1
-f () /* { dg-error {'coro1::promise_type::get_return_object_on_allocation_failure\(\)\(\)' is provided by 'std::__n4861::__coroutine_traits_impl::promise_type' \{aka 'coro1::promise_type'\} but 'operator new' is not marked 'throw\(\)' or 'noexcept'} } */
+f () /* { dg-error {'coro1::promise_type::get_return_object_on_allocation_failure\(\)\(\)' is provided by 'std::(__8::)?__n4861::__coroutine_traits_impl::promise_type' \{aka 'coro1::promise_type'\} but 'operator new' is not marked 'throw\(\)' or 'noexcept'} } */
 {
   co_return;
 }
diff --git a/gcc/testsuite/g++.dg/coroutines/coro-bad-grooaf-01-grooaf-expected.C b/gcc/testsuite/g++.dg/coroutines/coro-bad-grooaf-01-grooaf-expected.C
index 9fa3d64a9f2..b36e88f871a 100644
--- a/gcc/testsuite/g++.dg/coroutines/coro-bad-grooaf-01-grooaf-expected.C
+++ b/gcc/testsuite/g++.dg/coroutines/coro-bad-grooaf-01-grooaf-expected.C
@@ -6,7 +6,7 @@
 int used_grooaf = 0;
 
 struct coro1
-f () noexcept // { dg-warning {'operator new' is marked 'throw\(\)' or 'noexcept' but no usable 'get_return_object_on_allocation_failure' is provided by 'std::__n4861::__coroutine_traits_impl::promise_type' \{aka 'coro1::promise_type'\}} }
+f () noexcept // { dg-warning {'operator new' is marked 'throw\(\)' or 'noexcept' but no usable 'get_return_object_on_allocation_failure' is provided by 'std::(__8::)?__n4861::__coroutine_traits_impl::promise_type' \{aka 'coro1::promise_type'\}} }
 {
   PRINT ("coro1: about to return");
   co_return;
diff --git a/gcc/testsuite/g++.dg/coroutines/pr97438.C b/gcc/testsuite/g++.dg/coroutines/pr97438.C
index 95376648ed7..ac37118eae7 100644
--- a/gcc/testsuite/g++.dg/corouti

Re: [PATCH][_GLIBCXX_INLINE_VERSION] Fix

2023-09-20 Thread François Dumont
libstdc++: [_GLIBCXX_INLINE_VERSION] Add handle_contract_violation 
symbol alias


libstdc++-v3/ChangeLog:

    * src/experimental/contract.cc
    [_GLIBCXX_INLINE_VERSION](handle_contract_violation): Provide 
symbol alias

    without version namespace decoration for gcc.

Here is what I'm testing eventually, ok to commit if successful ?

François

On 20/09/2023 11:32, Jonathan Wakely wrote:

On Wed, 20 Sept 2023 at 05:51, François Dumont via Libstdc++
 wrote:

libstdc++: Remove std::constract_violation from versioned namespace

Spelling mistake in contract_violation, and it's not
std::contract_violation, it's std::experimental::contract_violation


GCC expects this type to be in std namespace directly.

Again, it's in std::experimental not in std directly.

Will this change cause problems when including another experimental
header, which does put experimental below std::__8?

I think std::__8::experimental and std::experimental will become ambiguous.

Maybe we do want to remove the inline __8 namespace from all
experimental headers. That needs a bit more thought though.


libstdc++-v3/ChangeLog:

  * include/experimental/contract:
  Remove _GLIBCXX_BEGIN_NAMESPACE_VERSION/_GLIBCXX_END_NAMESPACE_VERSION.

This line is too long for the changelog.


It does fix 29 g++.dg/contracts in gcc testsuite.

Ok to commit ?

Françoisdiff --git a/libstdc++-v3/src/experimental/contract.cc b/libstdc++-v3/src/experimental/contract.cc
index 504a6c041f1..17daa3312ca 100644
--- a/libstdc++-v3/src/experimental/contract.cc
+++ b/libstdc++-v3/src/experimental/contract.cc
@@ -67,3 +67,14 @@ handle_contract_violation (const std::experimental::contract_violation 
   std::cerr << std::endl;
 #endif
 }
+
+#if _GLIBCXX_INLINE_VERSION
+// Provide symbol alias without version namespace decoration for gcc.
+extern "C"
+void _Z25handle_contract_violationRKNSt12experimental18contract_violationE
+(const std::experimental::contract_violation )
+__attribute__ (
+(alias
+ ("_Z25handle_contract_violationRKNSt3__812experimental18contract_violationE"),
+ weak));
+#endif


Re: [PATCH][_GLIBCXX_INLINE_VERSION] Fix

2023-09-20 Thread François Dumont

Tests were successful, ok to commit ?

On 20/09/2023 19:51, François Dumont wrote:
libstdc++: [_GLIBCXX_INLINE_VERSION] Add handle_contract_violation 
symbol alias


libstdc++-v3/ChangeLog:

    * src/experimental/contract.cc
    [_GLIBCXX_INLINE_VERSION](handle_contract_violation): Provide 
symbol alias

    without version namespace decoration for gcc.

Here is what I'm testing eventually, ok to commit if successful ?

François

On 20/09/2023 11:32, Jonathan Wakely wrote:

On Wed, 20 Sept 2023 at 05:51, François Dumont via Libstdc++
 wrote:

libstdc++: Remove std::constract_violation from versioned namespace

Spelling mistake in contract_violation, and it's not
std::contract_violation, it's std::experimental::contract_violation


GCC expects this type to be in std namespace directly.

Again, it's in std::experimental not in std directly.

Will this change cause problems when including another experimental
header, which does put experimental below std::__8?

I think std::__8::experimental and std::experimental will become 
ambiguous.


Maybe we do want to remove the inline __8 namespace from all
experimental headers. That needs a bit more thought though.


libstdc++-v3/ChangeLog:

  * include/experimental/contract:
  Remove 
_GLIBCXX_BEGIN_NAMESPACE_VERSION/_GLIBCXX_END_NAMESPACE_VERSION.

This line is too long for the changelog.


It does fix 29 g++.dg/contracts in gcc testsuite.

Ok to commit ?

François


Re: [PATCH][_GLIBCXX_INLINE_VERSION] Fix

2023-10-08 Thread François Dumont
I think we can do the same without the symbol alias feature. It's even 
simpler cause do not require any maintenance when version symbol bump.


Here is what I'm testing, at least exported symbol is fine.

François


On 08/10/2023 16:06, Iain Sandoe wrote:

Hi François,


On 21 Sep 2023, at 05:41, François Dumont  wrote:

Tests were successful, ok to commit ?

On 20/09/2023 19:51, François Dumont wrote:

libstdc++: [_GLIBCXX_INLINE_VERSION] Add handle_contract_violation symbol alias

libstdc++-v3/ChangeLog:

 * src/experimental/contract.cc
 [_GLIBCXX_INLINE_VERSION](handle_contract_violation): Provide symbol alias
 without version namespace decoration for gcc.

This does not work in the source on targets without support for symbol aliases 
(Darwin is one)
“../experimental/contract.cc:79:8: warning: alias definitions not supported in 
Mach-O; ignored”

- there might be a way to do it at link-time (for one symbol not too bad); I 
will have to poke at
   it a bit.
Iain


Here is what I'm testing eventually, ok to commit if successful ?

François

On 20/09/2023 11:32, Jonathan Wakely wrote:

On Wed, 20 Sept 2023 at 05:51, François Dumont via Libstdc++
 wrote:

libstdc++: Remove std::constract_violation from versioned namespace

Spelling mistake in contract_violation, and it's not
std::contract_violation, it's std::experimental::contract_violation


GCC expects this type to be in std namespace directly.

Again, it's in std::experimental not in std directly.

Will this change cause problems when including another experimental
header, which does put experimental below std::__8?

I think std::__8::experimental and std::experimental will become ambiguous.

Maybe we do want to remove the inline __8 namespace from all
experimental headers. That needs a bit more thought though.


libstdc++-v3/ChangeLog:

   * include/experimental/contract:
   Remove _GLIBCXX_BEGIN_NAMESPACE_VERSION/_GLIBCXX_END_NAMESPACE_VERSION.

This line is too long for the changelog.


It does fix 29 g++.dg/contracts in gcc testsuite.

Ok to commit ?

Françoisdiff --git a/libstdc++-v3/src/experimental/contract.cc b/libstdc++-v3/src/experimental/contract.cc
index 504a6c041f1..7918e5ae53a 100644
--- a/libstdc++-v3/src/experimental/contract.cc
+++ b/libstdc++-v3/src/experimental/contract.cc
@@ -67,3 +67,12 @@ handle_contract_violation (const std::experimental::contract_violation 
   std::cerr << std::endl;
 #endif
 }
+
+#if _GLIBCXX_INLINE_VERSION
+// Provide symbol without version namespace decoration for gcc.
+extern "C"
+__attribute__ ((weak)) void
+_Z25handle_contract_violationRKNSt12experimental18contract_violationE
+(const std::experimental::contract_violation )
+{ handle_contract_violation(violation); }
+#endif


Re: [PATCH][_Hashtable] Avoid redundant usage of rehash policy

2023-10-12 Thread François Dumont

Now that abi breakage is fixed and hoping that Friday is review day :-)

Ping !

On 17/09/2023 22:41, François Dumont wrote:

libstdc++: [_Hashtable] Avoid redundant usage of rehash policy

Bypass usage of __detail::__distance_fwd and check for need to rehash 
when assigning an initializer_list to

an unordered_multimap or unordered_multiset.

libstdc++-v3/ChangeLog:

    * include/bits/hashtable_policy.h
    (_Insert_base<>::_M_insert_range(_InputIte, _InputIte, 
_NodeGen&)): New.
    (_Insert_base<>::_M_insert_range(_InputIte, _InputIte, 
true_type)): Use latter.
    (_Insert_base<>::_M_insert_range(_InputIte, _InputIte, 
false_type)): Likewise.

    * include/bits/hashtable.h
(_Hashtable<>::operator=(initializer_list)): Likewise.
    (_Hashtable<>::_Hashtable(_InputIte, _InputIte, size_type, const 
_Hash&, const _Equal&,

    const allocator_type&, false_type)): Likewise.

Ok to commit ?

François



[PATCH][_GLIBCXX_INLINE_VERSION] Add missing symbols

2023-10-05 Thread François Dumont

Here is a patch to fix following test case in gcc:

gcc/testsuite/g++.dg/cpp23/ext-floating13.C

    libstdc++: [_GLIBCXX_INLINE_VERSION] Add missing float symbols

    libstdc++-v3/ChangeLog:

    * config/abi/pre/gnu-versioned-namespace.ver: Add missing 
symbols

    for _Float{16,32,64,128,32x,64x,128x}.

Ok to commit ?

François

diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
index 267ab8fc719..9fab8bead15 100644
--- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
+++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
@@ -318,6 +318,15 @@ CXXABI_2.0 {
 _ZTIPD[fde];
 _ZTIPKD[fde];
 
+# typeinfo for _Float{16,32,64,128,32x,64x,128x} and
+# __bf16
+_ZTIDF[0-9]*[_bx];
+_ZTIPDF[0-9]*[_bx];
+_ZTIPKDF[0-9]*[_bx];
+_ZTIu6__bf16;
+_ZTIPu6__bf16;
+_ZTIPKu6__bf16;
+
 # typeinfo for decltype(nullptr)
 _ZTIDn;
 _ZTIPDn;


Re: [PATCH] sso-string@gnu-versioned-namespace [PR83077]

2023-10-07 Thread François Dumont
 * src/c++11/cxx11-locale-inst.cc: Cleanup, just include 
locale-inst.cc.
    * src/c++11/cxx11-stdexcept.cc [!_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cxx11-wlocale-inst.cc 
[!_GLIBCXX_USE_CXX11_ABI]: Skip definitions.

    * src/c++11/locale-inst-numeric.h
[!_GLIBCXX_USE_DUAL_ABI](std::use_facet>, 
std::use_facet>): Instantiate.
[!_GLIBCXX_USE_DUAL_ABI](std::has_facet>, 
std::has_facet>): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](std::num_getistreambuf_iterator>): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](std::num_putostreambuf_iterator>): Instantiate.
    * src/c++11/locale-inst.cc [!_GLIBCXX_USE_DUAL_ABI]: Build 
only when configured

    _GLIBCXX_USE_CXX11_ABI is equal to currently built abi.
    [!_GLIBCXX_USE_DUAL_ABI](__moneypunct_cache): 
Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](__moneypunct_cache): 
Instantiate.

    [!_GLIBCXX_USE_DUAL_ABI](__numpunct_cache): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](__timepunct): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](__timepunct_cache): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](time_putostreambuf_iterator>): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](time_put_bynameostreambuf_iterator>): Instantiate.

[!_GLIBCXX_USE_DUAL_ABI](__ctype_abstract_base): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](ctype_byname): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](__codecvt_abstract_basembstate_t>): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](codecvt_bynamembstate_t>): Instantiate.

[!_GLIBCXX_USE_DUAL_ABI](use_facet>(const locale&)): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](use_facetmbstate_t>>(const locale&)): Instantiate.
[!_GLIBCXX_USE_DUAL_ABI](use_facet<__timepunct>(const locale&)): 
Instantiate.
[!_GLIBCXX_USE_DUAL_ABI](use_facet>(const locale&)): 
Instantiate.

[!_GLIBCXX_USE_DUAL_ABI](has_facet>(const locale&)): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](has_facetmbstate_t>>(const locale&)): Instantiate.
[!_GLIBCXX_USE_DUAL_ABI](has_facet<__timepunct>(const locale&)): 
Instantiate.
[!_GLIBCXX_USE_DUAL_ABI](has_facet>(const locale&)): 
Instantiate.

    [!_GLIBCXX_USE_DUAL_ABI](__add_grouping): Define.
    [!_GLIBCXX_USE_DUAL_ABI](__pad>): 
Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](__int_to_char(C*, unsigned long, 
const C*,

    ios_base::fmtflags, bool)): Define.
    [!_GLIBCXX_USE_DUAL_ABI](__int_to_char(C*, unsigned long 
long, const C*,

    ios_base::fmtflags, bool)): Define.
    * src/c++11/wlocale-inst.cc [!_GLIBCXX_USE_CXX11_ABI]: Skip 
definitions.
    * src/c++98/Makefile.am (cxx11_abi_sources): Remove, unique 
cow-istream-string.cc entry

    move to...
    (inst_sources): ...this.
    * src/c++98/Makefile.in: Regenerate.
    * src/c++98/cow-istream-string.cc: Include .
    [_GLIBCXX_USE_CXX11_ABI]: Skip definitions.
    * src/c++98/hash_tr1.cc [_GLIBCXX_USE_CXX11_ABI]: Skip 
definitions.
    * src/c++98/ios_failure.cc 
[_GLIBCXX_USE_CXX11_ABI][_GLIBCXX_USE_DUAL_ABI]: Skip definitions.
    * src/c++98/istream-string.cc [!_GLIBCXX_USE_DUAL_ABI]: 
Build only when configured

    _GLIBCXX_USE_CXX11_ABI is equal to currently built abi.
    * src/c++98/locale_facets.cc 
[_GLIBCXX_USE_CXX11_ABI](__verify_grouping): Remove.

    * src/c++98/stdexcept.cc
    [_GLIBCXX_USE_CXX11_ABI](logic_error(const string&): Remove.
    [_GLIBCXX_USE_CXX11_ABI](domain_error(const string&): Remove.
    [_GLIBCXX_USE_CXX11_ABI](invalid_argument(const string&): 
Remove.

    [_GLIBCXX_USE_CXX11_ABI](length_error(const string&): Remove.
    [_GLIBCXX_USE_CXX11_ABI](out_of_range(const string&): Remove.
    [_GLIBCXX_USE_CXX11_ABI](runtime_error(const string&): Remove.
    [_GLIBCXX_USE_CXX11_ABI](range_error(const string&): Remove.
    [_GLIBCXX_USE_CXX11_ABI](overflow_error(const string&): Remove.
    [_GLIBCXX_USE_CXX11_ABI](underflow_error(const string&): 
Remove.
    * src/c++98/compatibility.cc [_GLIBCXX_USE_CXX11_ABI]: Skip 
all definitions appart from

    istream::ignore(streamsize).

Tested under Linux x64_86, ok to commit ?

François


On 17/08/2023 19:22, Jonathan Wakely wrote:

On Sun, 13 Aug 2023 at 14:27, François Dumont via Libstdc++
 wrote:

Here is the fixed patch tested in all 3 modes:

- _GLIBCXX_USE_DUAL_ABI

- !_GLIBCXX_USE_DUAL_ABI && !_GLIBCXX_USE_CXX11_ABI

- !_GLIBCXX_USE_DUAL_ABI && _GLIBCXX_USE_CXX11_ABI

I don't know what you have in mind for the change below but I wanted to
let you know that I tried to put COW std::basic_string into a nested
__cow namespace when _GLIBCXX_USE_CXX11_ABI. But it had more im

Re: [PATCH] sso-string@gnu-versioned-namespace [PR83077]

2023-10-07 Thread François Dumont
I've been told that previous patch generated with 'git diff -b' was not 
applying properly so here is the same patch again with a simple 'git diff'.



On 07/10/2023 14:25, François Dumont wrote:

Hi

Here is a rebased version of this patch.

There are few test failures when running 'make check-c++' but nothing 
new.


Still, there are 2 patches awaiting validation to fix some of them, PR 
c++/111524 to fix another bunch and I fear that we will have to live 
with the others.


    libstdc++: [_GLIBCXX_INLINE_VERSION] Use cxx11 abi [PR83077]

    Use cxx11 abi when activating versioned namespace mode. To do support
    a new configuration mode where !_GLIBCXX_USE_DUAL_ABI and 
_GLIBCXX_USE_CXX11_ABI.


    The main change is that std::__cow_string is now defined whenever 
_GLIBCXX_USE_DUAL_ABI
    or _GLIBCXX_USE_CXX11_ABI is true. Implementation is using 
available std::string in

    case of dual abi and a subset of it when it's not.

    On the other side std::__sso_string is defined only when 
_GLIBCXX_USE_DUAL_ABI is true
    and _GLIBCXX_USE_CXX11_ABI is false. Meaning that 
std::__sso_string is a typedef for the
    cow std::string implementation when dual abi is disabled and cow 
string is being used.


    libstdcxx-v3/ChangeLog:

    PR libstdc++/83077
    * acinclude.m4 [GLIBCXX_ENABLE_LIBSTDCXX_DUAL_ABI]: 
Default to "new" libstdcxx abi

    when enable_symvers is gnu-versioned-namespace.
    * config/locale/dragonfly/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Define money_base

    members.
    * config/locale/generic/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Likewise.
    * config/locale/gnu/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Likewise.

    * config/locale/gnu/numeric_members.cc
    [!_GLIBCXX_USE_DUAL_ABI](__narrow_multibyte_chars): Define.
    * configure: Regenerate.
    * include/bits/c++config
    [_GLIBCXX_INLINE_VERSION](_GLIBCXX_NAMESPACE_CXX11, 
_GLIBCXX_BEGIN_NAMESPACE_CXX11):

    Define empty.
[_GLIBCXX_INLINE_VERSION](_GLIBCXX_END_NAMESPACE_CXX11, 
_GLIBCXX_DEFAULT_ABI_TAG):

    Likewise.
    * include/bits/cow_string.h [!_GLIBCXX_USE_CXX11_ABI]: 
Define a light version of COW

    basic_string as __std_cow_string for use in stdexcept.
    * include/std/stdexcept [_GLIBCXX_USE_CXX11_ABI]: Define 
__cow_string.

    (__cow_string(const char*)): New.
    (__cow_string::c_str()): New.
    * python/libstdcxx/v6/printers.py 
(StdStringPrinter::__init__): Set self.new_string to True

    when std::__8::basic_string type is found.
    * src/Makefile.am 
[ENABLE_SYMVERS_GNU_NAMESPACE](ldbl_alt128_compat_sources): Define empty.

    * src/Makefile.in: Regenerate.
    * src/c++11/Makefile.am (cxx11_abi_sources): Rename into...
    (dual_abi_sources): ...this. Also move cow-local_init.cc, 
cxx11-hash_tr1.cc,

    cxx11-ios_failure.cc entries to...
    (sources): ...this.
    (extra_string_inst_sources): Move cow-fstream-inst.cc, 
cow-sstream-inst.cc, cow-string-inst.cc,
    cow-string-io-inst.cc, cow-wtring-inst.cc, 
cow-wstring-io-inst.cc, cxx11-locale-inst.cc,

    cxx11-wlocale-inst.cc entries to...
    (inst_sources): ...this.
    * src/c++11/Makefile.in: Regenerate.
    * src/c++11/cow-fstream-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cow-locale_init.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cow-sstream-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cow-stdexcept.cc [_GLIBCXX_USE_CXX11_ABI]: 
Include .
    [_GLIBCXX_USE_DUAL_ABI || 
_GLIBCXX_USE_CXX11_ABI](__cow_string): Redefine before
    including . Define 
_GLIBCXX_DEFINE_STDEXCEPT_INSTANTIATIONS so that

    __cow_string definition in  is skipped.
    [_GLIBCXX_USE_CXX11_ABI]: Skip Transaction Memory TS 
definitions.
    * src/c++11/string-inst.cc: Add sizeof/alignof 
static_assert on stdexcept

    __cow_string definition.
    (_GLIBCXX_DEFINING_CXX11_ABI_INSTANTIATIONS): Define 
following _GLIBCXX_USE_CXX11_ABI

    value.
    [_GLIBCXX_USE_CXX11_ABI && 
!_GLIBCXX_DEFINING_CXX11_ABI_INSTANTIATIONS]:
    Define _GLIBCXX_DEFINING_COW_STRING_INSTANTIATIONS. 
Include .
    Define basic_string as __std_cow_string for the current 
translation unit.
    * src/c++11/cow-string-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cow-string-io-inst.cc 
[_GLIBCXX_USE_CXX11_ABI]: Skip definitions.
    * src/c++11/cow-wstring-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cow-wstring-io-inst.cc 
[_GLIBCXX_USE_CXX11_ABI]: Skip definitions.
    * src/c++11/cxx11-hash_tr1.cc [!_GLIBCXX_USE

Re: [PATCH] sso-string@gnu-versioned-namespace [PR83077]

2023-10-09 Thread François Dumont



On 09/10/2023 16:42, Iain Sandoe wrote:

Hi François,


On 7 Oct 2023, at 20:32, François Dumont  wrote:

I've been told that previous patch generated with 'git diff -b' was not 
applying properly so here is the same patch again with a simple 'git diff'.

Thanks, that did fix it - There are some training whitespaces in the config 
files, but I suspect that they need to be there since those have values 
appended during the configuration.


You're talking about the ones coming from regenerated Makefile.in and 
configure I guess. I prefer not to edit those, those trailing 
whitespaces are already in.





Anyway, with this + the coroutines and contract v2 (weak def) fix, plus a local 
patch to enable versioned namespace on Darwin, I get results comparable with 
the non-versioned case - but one more patchlet is needed on  yours (to allow 
for targets using emultated TLS):

diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver 
b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
index 9fab8bead15..b7167fc0c2f 100644
--- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
+++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
@@ -78,6 +78,7 @@ GLIBCXX_8.0 {
  
  # thread/mutex/condition_variable/future

  __once_proxy;
+__emutls_v._ZNSt3__81?__once_call*;


I can add this one, sure, even if it could be part of a dedicated patch. 
I'm surprised that we do not need the __once_callable emul symbol too, 
it would be more consistent with the non-versioned mode.


I'm pretty sure there are a bunch of other symbols missing, but this 
mode is seldomly tested...


  
  # std::__convert_to_v

  _ZNSt3__814__convert_to_v*;


thanks
Iain



On 07/10/2023 14:25, François Dumont wrote:

Hi

Here is a rebased version of this patch.

There are few test failures when running 'make check-c++' but nothing new.

Still, there are 2 patches awaiting validation to fix some of them, PR 
c++/111524 to fix another bunch and I fear that we will have to live with the 
others.

 libstdc++: [_GLIBCXX_INLINE_VERSION] Use cxx11 abi [PR83077]

 Use cxx11 abi when activating versioned namespace mode. To do support
 a new configuration mode where !_GLIBCXX_USE_DUAL_ABI and 
_GLIBCXX_USE_CXX11_ABI.

 The main change is that std::__cow_string is now defined whenever 
_GLIBCXX_USE_DUAL_ABI
 or _GLIBCXX_USE_CXX11_ABI is true. Implementation is using available 
std::string in
 case of dual abi and a subset of it when it's not.

 On the other side std::__sso_string is defined only when 
_GLIBCXX_USE_DUAL_ABI is true
 and _GLIBCXX_USE_CXX11_ABI is false. Meaning that std::__sso_string is a 
typedef for the
 cow std::string implementation when dual abi is disabled and cow string is 
being used.

 libstdcxx-v3/ChangeLog:

 PR libstdc++/83077
 * acinclude.m4 [GLIBCXX_ENABLE_LIBSTDCXX_DUAL_ABI]: Default to 
"new" libstdcxx abi
 when enable_symvers is gnu-versioned-namespace.
 * config/locale/dragonfly/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Define money_base
 members.
 * config/locale/generic/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Likewise.
 * config/locale/gnu/monetary_members.cc [!_GLIBCXX_USE_DUAL_ABI]: 
Likewise.
 * config/locale/gnu/numeric_members.cc
 [!_GLIBCXX_USE_DUAL_ABI](__narrow_multibyte_chars): Define.
 * configure: Regenerate.
 * include/bits/c++config
 [_GLIBCXX_INLINE_VERSION](_GLIBCXX_NAMESPACE_CXX11, 
_GLIBCXX_BEGIN_NAMESPACE_CXX11):
 Define empty.
[_GLIBCXX_INLINE_VERSION](_GLIBCXX_END_NAMESPACE_CXX11, 
_GLIBCXX_DEFAULT_ABI_TAG):
 Likewise.
 * include/bits/cow_string.h [!_GLIBCXX_USE_CXX11_ABI]: Define a 
light version of COW
 basic_string as __std_cow_string for use in stdexcept.
 * include/std/stdexcept [_GLIBCXX_USE_CXX11_ABI]: Define 
__cow_string.
 (__cow_string(const char*)): New.
 (__cow_string::c_str()): New.
 * python/libstdcxx/v6/printers.py (StdStringPrinter::__init__): 
Set self.new_string to True
 when std::__8::basic_string type is found.
 * src/Makefile.am 
[ENABLE_SYMVERS_GNU_NAMESPACE](ldbl_alt128_compat_sources): Define empty.
 * src/Makefile.in: Regenerate.
 * src/c++11/Makefile.am (cxx11_abi_sources): Rename into...
 (dual_abi_sources): ...this. Also move cow-local_init.cc, 
cxx11-hash_tr1.cc,
 cxx11-ios_failure.cc entries to...
 (sources): ...this.
 (extra_string_inst_sources): Move cow-fstream-inst.cc, 
cow-sstream-inst.cc, cow-string-inst.cc,
 cow-string-io-inst.cc, cow-wtring-inst.cc, cow-wstring-io-inst.cc, 
cxx11-locale-inst.cc,
 cxx11-wlocale-inst.cc entries to...
 (inst_sources): ...this.
 * src/c++11/M

Re: [PATCH] Fix coroutine tests for libstdc++ gnu-version-namespace mode

2023-10-10 Thread François Dumont



On 08/10/2023 15:59, Iain Sandoe wrote:

Hi François,


On 23 Sep 2023, at 21:10, François Dumont  wrote:

I'm eventually fixing those tests the same way we manage this problem in 
libstdc++ testsuite.

testsuite: Add optional libstdc++ version namespace in expected diagnostic

 When libstdc++ is build with --enable-symvers=gnu-versioned-namespace 
diagnostics are
 showing this namespace, currently __8.

 gcc/testsuite/ChangeLog:

 * testsuite/g++.dg/coroutines/coro-bad-alloc-00-bad-op-new.C: Add 
optional
 '__8' version namespace in expected diagnostic.
 * testsuite/g++.dg/coroutines/coro-bad-alloc-01-bad-op-del.C: 
Likewise.
 * testsuite/g++.dg/coroutines/coro-bad-alloc-02-no-op-new-nt.C: 
Likewise.
 * 
testsuite/g++.dg/coroutines/coro-bad-grooaf-01-grooaf-expected.C: Likewise.
 * testsuite/g++.dg/coroutines/pr97438.C: Likewise.
 * testsuite/g++.dg/coroutines/ramp-return-b.C: Likewise.

Tested under Linux x86_64.

I'm contributing to libstdc++ so I already have write access.

Ok to commit ?

As author of the tests, this LGTM as a suitable fix for now (at least, once the 
main
patch to fix versioned namespaces lands).


I just realized it was a "go", no ? Then why after the main patch ?

The "main patch" do not fix the versioned namespace. It just makes it 
adopt the cxx11 abi.


This patch fixes a problem that is as old as the tests and that is 
totally unrelated with the main one. I just wanted to improve the 
situation so that versioned namespace mode do not look more buggy than 
necessary when someone (like you) run those.




However, IMO, this could become quite painful as more g++ tests make use of std 
headers
(which is not really optional for facilities like this that are tightly-coupled 
between the FE and
the library).

For the future, it does seem that a more complete solution might be to 
introduce a
testsuite-wide definition for the C++ versioned std:: introducer, so that we 
can update it in one
place as the version changes.

So (as a thought experiment):
  - we’d have something of the form “CXX_STD” as a tcl global
  - we’d add the presence/absence of versioning to the relevant site.exp (which
means recognising the versioning choice also in the GCC configure)
  - we’d migrate tests to using ${CXX_STD} instead of "std::__N”  in matches

… I guess an alternative could be to cook up some alternate warning/error/etc
match functions that cater for arbitrary inline namespaces but that seems 
like a much
more tricky and invasive testsuite change.

thoughts?


I considered amending gcc/testsuite/lib/prune.exp to simply remove the 
version from the diagnostic. But the reply on why it was not working 
scared me, so this patch.


https://gcc.gnu.org/pipermail/gcc/2023-September/242526.html



Re: [PATCH][_Hashtable] Fix merge

2023-10-19 Thread François Dumont

Committed with the advised changes.

Ok, I'll backport next week.

Thanks

On 19/10/2023 10:05, Jonathan Wakely wrote:



On Thursday, 19 October 2023, François Dumont  
wrote:

> libstdc++: [_Hashtable] Do not reuse untrusted cached hash code
>
> On merge reuse merged node cached hash code only if we are on the 
same type of
> hash and this hash is stateless. Usage of function pointers or 
std::function as

> hash functor will prevent this optimization.

I found this first sentence a little hard to parse. How about:

On merge, reuse a merged node's cached hash code only if we are on the 
same

type of
hash and this hash is stateless.


And for the second sentence, would it be clearer to say "will prevent 
reusing cached hash codes" instead of "will prevent this optimization"?



And for the comment on the new function, I think this reads better:

"Only use the node's (possibly cached) hash code if its hash function 
_H2 matches _Hash. Otherwise recompute it using _Hash."


The code and tests look good, so if you're happy with the 
comment+changelog suggestions, this is ok for trunk.


This seems like a bug fix that should be backported too, after some 
time on trunk.



>
> libstdc++-v3/ChangeLog
>
>     * include/bits/hashtable_policy.h
>     (_Hash_code_base::_M_hash_code(const _Hash&, const 
_Hash_node_value<>&)): Remove.
>     (_Hash_code_base::_M_hash_code<_H2>(const _H2&, const 
_Hash_node_value<>&)): Remove.

>     * include/bits/hashtable.h
>     (_M_src_hash_code<_H2>(const _H2&, const key_type&, const 
__node_value_type&)): New.

>     (_M_merge_unique<>, _M_merge_multi<>): Use latter.
>     * testsuite/23_containers/unordered_map/modifiers/merge.cc
>     (test04, test05, test06): New test cases.
>
> Tested under Linux x86_64, ok to commit ?
>
> François
>
> 

Re: [PATCH] sso-string@gnu-versioned-namespace [PR83077]

2023-10-23 Thread François Dumont

Hi

Still no one to complete this review ?

Thanks


On 07/10/2023 21:32, François Dumont wrote:
I've been told that previous patch generated with 'git diff -b' was 
not applying properly so here is the same patch again with a simple 
'git diff'.



On 07/10/2023 14:25, François Dumont wrote:

Hi

Here is a rebased version of this patch.

There are few test failures when running 'make check-c++' but nothing 
new.


Still, there are 2 patches awaiting validation to fix some of them, 
PR c++/111524 to fix another bunch and I fear that we will have to 
live with the others.


    libstdc++: [_GLIBCXX_INLINE_VERSION] Use cxx11 abi [PR83077]

    Use cxx11 abi when activating versioned namespace mode. To do 
support
    a new configuration mode where !_GLIBCXX_USE_DUAL_ABI and 
_GLIBCXX_USE_CXX11_ABI.


    The main change is that std::__cow_string is now defined whenever 
_GLIBCXX_USE_DUAL_ABI
    or _GLIBCXX_USE_CXX11_ABI is true. Implementation is using 
available std::string in

    case of dual abi and a subset of it when it's not.

    On the other side std::__sso_string is defined only when 
_GLIBCXX_USE_DUAL_ABI is true
    and _GLIBCXX_USE_CXX11_ABI is false. Meaning that 
std::__sso_string is a typedef for the
    cow std::string implementation when dual abi is disabled and cow 
string is being used.


    libstdcxx-v3/ChangeLog:

    PR libstdc++/83077
    * acinclude.m4 [GLIBCXX_ENABLE_LIBSTDCXX_DUAL_ABI]: 
Default to "new" libstdcxx abi

    when enable_symvers is gnu-versioned-namespace.
    * config/locale/dragonfly/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Define money_base

    members.
    * config/locale/generic/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Likewise.
    * config/locale/gnu/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Likewise.

    * config/locale/gnu/numeric_members.cc
    [!_GLIBCXX_USE_DUAL_ABI](__narrow_multibyte_chars): Define.
    * configure: Regenerate.
    * include/bits/c++config
    [_GLIBCXX_INLINE_VERSION](_GLIBCXX_NAMESPACE_CXX11, 
_GLIBCXX_BEGIN_NAMESPACE_CXX11):

    Define empty.
[_GLIBCXX_INLINE_VERSION](_GLIBCXX_END_NAMESPACE_CXX11, 
_GLIBCXX_DEFAULT_ABI_TAG):

    Likewise.
    * include/bits/cow_string.h [!_GLIBCXX_USE_CXX11_ABI]: 
Define a light version of COW

    basic_string as __std_cow_string for use in stdexcept.
    * include/std/stdexcept [_GLIBCXX_USE_CXX11_ABI]: Define 
__cow_string.

    (__cow_string(const char*)): New.
    (__cow_string::c_str()): New.
    * python/libstdcxx/v6/printers.py 
(StdStringPrinter::__init__): Set self.new_string to True

    when std::__8::basic_string type is found.
    * src/Makefile.am 
[ENABLE_SYMVERS_GNU_NAMESPACE](ldbl_alt128_compat_sources): Define 
empty.

    * src/Makefile.in: Regenerate.
    * src/c++11/Makefile.am (cxx11_abi_sources): Rename into...
    (dual_abi_sources): ...this. Also move cow-local_init.cc, 
cxx11-hash_tr1.cc,

    cxx11-ios_failure.cc entries to...
    (sources): ...this.
    (extra_string_inst_sources): Move cow-fstream-inst.cc, 
cow-sstream-inst.cc, cow-string-inst.cc,
    cow-string-io-inst.cc, cow-wtring-inst.cc, 
cow-wstring-io-inst.cc, cxx11-locale-inst.cc,

    cxx11-wlocale-inst.cc entries to...
    (inst_sources): ...this.
    * src/c++11/Makefile.in: Regenerate.
    * src/c++11/cow-fstream-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cow-locale_init.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cow-sstream-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cow-stdexcept.cc [_GLIBCXX_USE_CXX11_ABI]: 
Include .
    [_GLIBCXX_USE_DUAL_ABI || 
_GLIBCXX_USE_CXX11_ABI](__cow_string): Redefine before
    including . Define 
_GLIBCXX_DEFINE_STDEXCEPT_INSTANTIATIONS so that

    __cow_string definition in  is skipped.
    [_GLIBCXX_USE_CXX11_ABI]: Skip Transaction Memory TS 
definitions.
    * src/c++11/string-inst.cc: Add sizeof/alignof 
static_assert on stdexcept

    __cow_string definition.
    (_GLIBCXX_DEFINING_CXX11_ABI_INSTANTIATIONS): Define 
following _GLIBCXX_USE_CXX11_ABI

    value.
    [_GLIBCXX_USE_CXX11_ABI && 
!_GLIBCXX_DEFINING_CXX11_ABI_INSTANTIATIONS]:
    Define _GLIBCXX_DEFINING_COW_STRING_INSTANTIATIONS. 
Include .
    Define basic_string as __std_cow_string for the current 
translation unit.
    * src/c++11/cow-string-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cow-string-io-inst.cc 
[_GLIBCXX_USE_CXX11_ABI]: Skip definitions.
    * src/c++11/cow-wstring-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cow-

[PATCH][_Hahstable] Use RAII to guard node pointer while constructing

2023-11-08 Thread François Dumont

Another proposal to use RAII rather than __try/__catch block.

libstdc++: [_Hashtable] Use RAII type to guard node while constructing value

libstdc++-v3/ChangeLog:

    * include/bits/hashtable_policy.h
    (struct _NodePtrGuard<_HashtableAlloc, _NodePtr>): New.
    (_ReuseAllocNode::operator()(_Args&&...)): Use latter to guard 
allocated node

    pointer while constructing in place the value_type instance.

Tested under Linux x64, ok to commit ?

François
diff --git a/libstdc++-v3/include/bits/hashtable_policy.h 
b/libstdc++-v3/include/bits/hashtable_policy.h
index cd8943d8d05..c67eebd3b2b 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -173,6 +173,19 @@ namespace __detail
{ return __node_gen(std::forward<_Kt>(__k)); }
 };
 
+  template
+struct _NodePtrGuard
+{
+  _HashtableAlloc& _M_h;
+  _NodePtr _M_ptr;
+
+  ~_NodePtrGuard()
+  {
+   if (_M_ptr)
+ _M_h._M_deallocate_node_ptr(_M_ptr);
+  }
+};
+
   template
 struct _Hashtable_alloc;
 
@@ -201,27 +214,20 @@ namespace __detail
__node_ptr
operator()(_Args&&... __args) const
{
- if (_M_nodes)
-   {
+ if (!_M_nodes)
+   return _M_h._M_allocate_node(std::forward<_Args>(__args)...);
+
  __node_ptr __node = _M_nodes;
  _M_nodes = _M_nodes->_M_next();
  __node->_M_nxt = nullptr;
  auto& __a = _M_h._M_node_allocator();
  __node_alloc_traits::destroy(__a, __node->_M_valptr());
- __try
-   {
+ _NodePtrGuard<__hashtable_alloc, __node_ptr> __guard { _M_h, __node };
  __node_alloc_traits::construct(__a, __node->_M_valptr(),
 std::forward<_Args>(__args)...);
-   }
- __catch(...)
-   {
- _M_h._M_deallocate_node_ptr(__node);
- __throw_exception_again;
-   }
+ __guard._M_ptr = nullptr;
  return __node;
}
- return _M_h._M_allocate_node(std::forward<_Args>(__args)...);
-   }
 
 private:
   mutable __node_ptr _M_nodes;


[PATCH][_GLIBCXX_DEBUG] Fix std::__niter_base behavior

2024-02-14 Thread François Dumont

libstdc++: [_GLIBCXX_DEBUG] Fix std::__niter_base behavior

std::__niter_base is used in _GLIBCXX_DEBUG mode to remove _Safe_iterator<>
wrapper on random access iterators. But doing so it should also preserve 
original

behavior to remove __normal_iterator wrapper.

libstdc++-v3/ChangeLog:

    * include/bits/stl_algobase.h (std::__niter_base): Redefine the 
overload

    definitions for __gnu_debug::_Safe_iterator.
    * include/debug/safe_iterator.tcc (std::__niter_base): Adapt 
declarations.


Ok to commit once all tests completed (still need to check pre-c++11) ?

François
diff --git a/libstdc++-v3/include/bits/stl_algobase.h 
b/libstdc++-v3/include/bits/stl_algobase.h
index e7207f67266..056fa0c4173 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -317,12 +317,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)
 { return __it; }
 
+#if __cplusplus < 201103L
   template
-_GLIBCXX20_CONSTEXPR
 _Ite
 __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
 std::random_access_iterator_tag>&);
 
+ template
+_Ite
+__niter_base(const ::__gnu_debug::_Safe_iterator<
+::__gnu_cxx::__normal_iterator<_Ite, _Cont>, _Seq,
+std::random_access_iterator_tag>&);
+#else
+  template
+_GLIBCXX20_CONSTEXPR
+decltype(std::__niter_base(std::declval<_Ite>()))
+__niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
+std::random_access_iterator_tag>&)
+noexcept( noexcept(std::is_nothrow_copy_constructible<
+   decltype(std::__niter_base(std::declval<_Ite>()))>::value) );
+#endif
+
   // Reverse the __niter_base transformation to get a
   // __normal_iterator back again (this assumes that __normal_iterator
   // is only used to wrap random access iterators, like pointers).
diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc 
b/libstdc++-v3/include/debug/safe_iterator.tcc
index 6eb70cbda04..d6cfe24cc83 100644
--- a/libstdc++-v3/include/debug/safe_iterator.tcc
+++ b/libstdc++-v3/include/debug/safe_iterator.tcc
@@ -235,13 +235,29 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+#if __cplusplus < 201103L
   template
-_GLIBCXX20_CONSTEXPR
 _Ite
 __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
 std::random_access_iterator_tag>& __it)
 { return __it.base(); }
 
+  template
+_Ite
+__niter_base(const ::__gnu_debug::_Safe_iterator<
+::__gnu_cxx::__normal_iterator<_Ite, _Cont>, _DbgSeq,
+std::random_access_iterator_tag>& __it)
+{ return __it.base().base(); }
+#else
+  template
+_GLIBCXX20_CONSTEXPR
+auto
+__niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
+std::random_access_iterator_tag>& __it)
+-> decltype(std::__niter_base(declval<_Ite>()))
+{ return std::__niter_base(__it.base()); }
+#endif
+
   template
 _GLIBCXX20_CONSTEXPR


Re: [PATCH][_GLIBCXX_DEBUG] Fix std::__niter_base behavior

2024-02-14 Thread François Dumont


On 14/02/2024 20:44, Jonathan Wakely wrote:



On Wed, 14 Feb 2024 at 18:39, François Dumont  
wrote:


libstdc++: [_GLIBCXX_DEBUG] Fix std::__niter_base behavior

std::__niter_base is used in _GLIBCXX_DEBUG mode to remove
_Safe_iterator<>
wrapper on random access iterators. But doing so it should also
preserve
original
behavior to remove __normal_iterator wrapper.

libstdc++-v3/ChangeLog:

 * include/bits/stl_algobase.h (std::__niter_base): Redefine the
overload
 definitions for __gnu_debug::_Safe_iterator.
 * include/debug/safe_iterator.tcc (std::__niter_base): Adapt
declarations.

Ok to commit once all tests completed (still need to check
pre-c++11) ?



The declaration in  include/bits/stl_algobase.h has a 
noexcept-specifier but the definition in 
include/debug/safe_iterator.tcc does not have one - that seems wrong 
(I'm surprised it even compiles).


It does ! I thought it was only necessary at declaration, and I also had 
troubles doing it right at definition because of the interaction with 
the auto and ->. Now simplified and consistent in this new proposal.



Just using std::is_nothrow_copy_constructible<_Ite> seems simpler, 
that will be true for __normal_iterator if 
is_nothrow_copy_constructible is true.



Ok


The definition in include/debug/safe_iterator.tcc should use 
std::declval<_Ite>() not declval<_Ite>(). Is there any reason why the 
definition uses a late-specified-return-type (i.e. auto and ->) when 
the declaration doesn't?



I initially plan to use '-> 
std::decltype(std::__niter_base(__it.base()))' but this did not compile, 
ambiguity issue. So I resort to using std::declval and I could have then 
done it the same way as declaration, done now.


Attached is what I'm testing, ok to commit once fully tested ?

François

diff --git a/libstdc++-v3/include/bits/stl_algobase.h 
b/libstdc++-v3/include/bits/stl_algobase.h
index e7207f67266..0f73da13172 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -317,12 +317,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)
 { return __it; }
 
+#if __cplusplus < 201103L
   template
-_GLIBCXX20_CONSTEXPR
 _Ite
 __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
 std::random_access_iterator_tag>&);
 
+ template
+_Ite
+__niter_base(const ::__gnu_debug::_Safe_iterator<
+::__gnu_cxx::__normal_iterator<_Ite, _Cont>, _Seq,
+std::random_access_iterator_tag>&);
+#else
+  template
+_GLIBCXX20_CONSTEXPR
+decltype(std::__niter_base(std::declval<_Ite>()))
+__niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
+std::random_access_iterator_tag>&)
+noexcept(std::is_nothrow_copy_constructible<_Ite>::value);
+#endif
+
   // Reverse the __niter_base transformation to get a
   // __normal_iterator back again (this assumes that __normal_iterator
   // is only used to wrap random access iterators, like pointers).
diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc 
b/libstdc++-v3/include/debug/safe_iterator.tcc
index 6eb70cbda04..a8b24233e85 100644
--- a/libstdc++-v3/include/debug/safe_iterator.tcc
+++ b/libstdc++-v3/include/debug/safe_iterator.tcc
@@ -235,13 +235,29 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+#if __cplusplus < 201103L
   template
-_GLIBCXX20_CONSTEXPR
 _Ite
 __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
 std::random_access_iterator_tag>& __it)
 { return __it.base(); }
 
+  template
+_Ite
+__niter_base(const ::__gnu_debug::_Safe_iterator<
+::__gnu_cxx::__normal_iterator<_Ite, _Cont>, _DbgSeq,
+std::random_access_iterator_tag>& __it)
+{ return __it.base().base(); }
+#else
+  template
+_GLIBCXX20_CONSTEXPR
+decltype(std::__niter_base(std::declval<_Ite>()))
+__niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
+std::random_access_iterator_tag>& __it)
+noexcept(std::is_nothrow_copy_constructible<_Ite>::value)
+{ return std::__niter_base(__it.base()); }
+#endif
+
   template
 _GLIBCXX20_CONSTEXPR


Re: [PATCH][_GLIBCXX_DEBUG] Fix std::__niter_base behavior

2024-02-15 Thread François Dumont


On 15/02/2024 14:17, Jonathan Wakely wrote:



On Wed, 14 Feb 2024 at 21:48, François Dumont  
wrote:



On 14/02/2024 20:44, Jonathan Wakely wrote:



On Wed, 14 Feb 2024 at 18:39, François Dumont
 wrote:

libstdc++: [_GLIBCXX_DEBUG] Fix std::__niter_base behavior

std::__niter_base is used in _GLIBCXX_DEBUG mode to remove
_Safe_iterator<>
wrapper on random access iterators. But doing so it should
also preserve
original
behavior to remove __normal_iterator wrapper.

libstdc++-v3/ChangeLog:

 * include/bits/stl_algobase.h (std::__niter_base):
Redefine the
overload
 definitions for __gnu_debug::_Safe_iterator.
 * include/debug/safe_iterator.tcc (std::__niter_base):
Adapt
declarations.

Ok to commit once all tests completed (still need to check
pre-c++11) ?



The declaration in  include/bits/stl_algobase.h has a
noexcept-specifier but the definition in
include/debug/safe_iterator.tcc does not have one - that seems
wrong (I'm surprised it even compiles).


It does !


The diagnostic is suppressed without -Wsystem-headers:

/home/jwakely/gcc/14/include/c++/14.0.1/debug/safe_iterator.tcc:255:5:warning: 
declaration of 'template constexpr decltype 
(std::__
niter_base(declval<_Ite>())) std::__niter_base(const 
__gnu_debug::_Safe_iterator<_Iterator, _Sequence, 
random_access_iterator_tag>&)' has a different except

ion specifier [-Wsystem-headers]
 255 | __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
 | ^~~~
/home/jwakely/gcc/14/include/c++/14.0.1/bits/stl_algobase.h:335:5:note: 
from previous declaration 'template constexpr 
decltype (std
::__niter_base(declval<_Ite>())) std::__niter_base(const 
__gnu_debug::_Safe_iterator<_Iterator, _Sequence, 
random_access_iterator_tag>&) noexcept (noexcept
(is_nothrow_copy_constructible(std::__niter_base(declval<_Ite>()))>::value))'

 335 | __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
 | ^~~~


It's a hard error with Clang though:

deb.cc:7:10: error: call to '__niter_base' is ambiguous



Yes, I eventually got the error too, I hadn't run enough tests yet.





I thought it was only necessary at declaration, and I also had
troubles doing it right at definition because of the interaction
with the auto and ->.


The trailing-return-type has to come after the noexcept-specifier.

Now simplified and consistent in this new proposal.



Just using std::is_nothrow_copy_constructible<_Ite> seems
simpler, that will be true for __normal_iterator if
is_nothrow_copy_constructible is true.


Ok



The definition in include/debug/safe_iterator.tcc should use
std::declval<_Ite>() not declval<_Ite>(). Is there any reason why
the definition uses a late-specified-return-type (i.e. auto and
->) when the declaration doesn't?



I initially plan to use '->
std::decltype(std::__niter_base(__it.base()))' but this did not
compile, ambiguity issue. So I resort to using std::declval and I
could have then done it the same way as declaration, done now.

Attached is what I'm testing, ok to commit once fully tested ?


OK, thanks.


Thanks for validation but I have a problem to test for c++98.

When I do:

make CXXFLAGS=-std=c++98 check-debug

I see in debug/libstdc++.log for example:

Executing on host: /home/fdumont/dev/gcc/build/./gcc/xg++ -shared-libgcc 
... -mshstk -std=c++98 -g -O2 -DLOCALEDIR="." -nostdinc++ 
-I/home/fdumont/dev/gcc/... 
/home/fdumont/dev/gcc/git/libstdc++-v3/testsuite/25_algorithms/copy/3.cc 
-D_GLIBCXX_DEBUG   -std=gnu++17  -include bits/stdc++.h ...  -lm -o 
./3.exe    (timeout = 360)


The -std=c++98 is there but later comes the -std=gnu++17 so I think it 
runs in C++17, no ?


I also tried the documented alternative:

make check 
'RUNTESTFLAGS=--target_board=unix/-O3\"{-std=gnu++98,-std=gnu++11,-std=gnu++14}\"'

but same problem, -std=gnu++17 comes last.

I'll try to rebuild all from scratch but I won't commit soon then.



Re: [PATCH][_GLIBCXX_DEBUG] Fix std::__niter_base behavior

2024-02-19 Thread François Dumont
Turns out that 23_containers/vector/erasure.cc was showing the problem 
in _GLIBCXX_DEBUG mode.


I had only run 25_algorithms tests in _GLIBCXX_DEBUG mode.

This is what I'm testing, I 'll let you know tomorrow morning if all 
successful.


Of course feel free to do or ask for a revert instead.

François


On 19/02/2024 09:21, Jonathan Wakely wrote:



On Mon, 19 Feb 2024, 08:12 Jonathan Wakely,  wrote:



On Mon, 19 Feb 2024, 07:08 Stephan Bergmann, 
wrote:

On 2/17/24 15:14, François Dumont wrote:
> Thanks for the link, tested and committed.

I assume this is the cause for the below failure now,


Yes, the new >= C++11 overload of __niter_base recursively unwraps
multiple layers of wrapping, so that a safe iterator wrapping a
normal iterator wrapping a pointer is unwrapped to just a pointer.
But then __niter_wrap doesn't restore both layers.



Actually that's not the problem. __niter_wrap would restore both 
layers, except that it uses __niter_base itself:


>   347 |     { return __from + (__res - std::__niter_base(__from)); }
>       |  ~~~^~~~

And it seems to be getting called with the wrong types. Maybe that's 
just a bug in std:: erase or maybe niter_wrap needs adjusting.


I'll check in a couple of hours if François doesn't get to it first.

I have to wonder how this wasn't caught by existing tests though.


diff --git a/libstdc++-v3/include/bits/stl_algobase.h 
b/libstdc++-v3/include/bits/stl_algobase.h
index 0f73da13172..d534e02871f 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -344,7 +344,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 _GLIBCXX20_CONSTEXPR
 inline _From
 __niter_wrap(_From __from, _To __res)
-{ return __from + (__res - std::__niter_base(__from)); }
+{ return __from + (std::__niter_base(__res) - std::__niter_base(__from)); }
 
   // No need to wrap, iterator already has the right type.
   template


Re: [PATCH][_GLIBCXX_DEBUG] Fix std::__niter_base behavior

2024-02-20 Thread François Dumont

   libstdc++: [_GLIBCXX_DEBUG] Fix std::__niter_wrap behavior

    In _GLIBCXX_DEBUG mode the std::__niter_base can remove 2 layers, the
    __gnu_debug::_Safe_iterator<> and the __gnu_cxx::__normal_iterator<>.
    When std::__niter_wrap is called to build a 
__gnu_debug::_Safe_iterator<>

    from a __gnu_cxx::__normal_iterator<> we then have a consistency issue
    as the difference between the 2 iterators will done on a 
__normal_iterator

    on one side and a C pointer on the other. To avoid this problem call
    std::__niter_base on both input iterators.

    libstdc++-v3/ChangeLog:

    * include/bits/stl_algobase.h (std::__niter_wrap): Add a 
call to

    std::__niter_base on res iterator.

Tested under Linux x86_64 normal and _GLIBCXX_DEBUG modes in c++98, 
c++11, c++17.


Ok to commit ?

François


On 19/02/2024 09:21, Jonathan Wakely wrote:



On Mon, 19 Feb 2024, 08:12 Jonathan Wakely,  wrote:



On Mon, 19 Feb 2024, 07:08 Stephan Bergmann, 
wrote:

    On 2/17/24 15:14, François Dumont wrote:
> Thanks for the link, tested and committed.

I assume this is the cause for the below failure now,


Yes, the new >= C++11 overload of __niter_base recursively unwraps
multiple layers of wrapping, so that a safe iterator wrapping a
normal iterator wrapping a pointer is unwrapped to just a pointer.
But then __niter_wrap doesn't restore both layers.



Actually that's not the problem. __niter_wrap would restore both 
layers, except that it uses __niter_base itself:


>   347 |     { return __from + (__res - std::__niter_base(__from)); }
>       |  ~~~^~~~

And it seems to be getting called with the wrong types. Maybe that's 
just a bug in std:: erase or maybe niter_wrap needs adjusting.


I'll check in a couple of hours if François doesn't get to it first.

I have to wonder how this wasn't caught by existing tests though.


diff --git a/libstdc++-v3/include/bits/stl_algobase.h 
b/libstdc++-v3/include/bits/stl_algobase.h
index 0f73da13172..d534e02871f 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -344,7 +344,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 _GLIBCXX20_CONSTEXPR
 inline _From
 __niter_wrap(_From __from, _To __res)
-{ return __from + (__res - std::__niter_base(__from)); }
+{ return __from + (std::__niter_base(__res) - std::__niter_base(__from)); }
 
   // No need to wrap, iterator already has the right type.
   template


[PATCH][_GLIBCXX_INLINE_VERSION] Adapt dg-error messages

2024-02-21 Thread François Dumont
For those using my patch to build in gnu-versioned-namespace mode it 
would be preferable not to have any failures when running testsuite.


    libstdc++: [_GLIBCXX_INLINE_VERSION] Adapt dg-error message

    libstdc++-v3/ChangeLog:

    * testsuite/20_util/function_objects/bind_back/111327.cc: 
Adapt dg-error message

    for __8 namespace.
    * testsuite/20_util/function_objects/bind_front/111327.cc: 
Likewise.


Ok to commit ?

François
diff --git 
a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/111327.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/111327.cc
index d634db9dc1d..f8a65127ccf 100644
--- a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/111327.cc
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/111327.cc
@@ -39,4 +39,4 @@ int main() {
   std::move(std::as_const(g1))();
 }
 
-// { dg-error "no type named 'type' in 'struct std::invoke_result" "" { target 
c++23 } 0 }
+// { dg-error "no type named 'type' in 'struct std::(__8::)?invoke_result" "" 
{ target c++23 } 0 }
diff --git 
a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc
index 5fe0a83baec..896492b3d74 100644
--- a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc
@@ -39,4 +39,4 @@ int main() {
   std::move(std::as_const(g1))();
 }
 
-// { dg-error "no type named 'type' in 'struct std::invoke_result" "" { target 
c++23 } 0 }
+// { dg-error "no type named 'type' in 'struct std::(__8::)?invoke_result" "" 
{ target c++23 } 0 }


Re: [PATCH][_GLIBCXX_DEBUG] Fix std::__niter_base behavior

2024-02-17 Thread François Dumont

Thanks for the link, tested and committed.

On 15/02/2024 19:40, Jonathan Wakely wrote:



On Thu, 15 Feb 2024 at 18:38, François Dumont  
wrote:



On 15/02/2024 14:17, Jonathan Wakely wrote:



On Wed, 14 Feb 2024 at 21:48, François Dumont
 wrote:


On 14/02/2024 20:44, Jonathan Wakely wrote:



On Wed, 14 Feb 2024 at 18:39, François Dumont
 wrote:

libstdc++: [_GLIBCXX_DEBUG] Fix std::__niter_base behavior

std::__niter_base is used in _GLIBCXX_DEBUG mode to
remove _Safe_iterator<>
wrapper on random access iterators. But doing so it
should also preserve
original
behavior to remove __normal_iterator wrapper.

libstdc++-v3/ChangeLog:

 * include/bits/stl_algobase.h (std::__niter_base):
Redefine the
overload
 definitions for __gnu_debug::_Safe_iterator.
 * include/debug/safe_iterator.tcc
(std::__niter_base): Adapt
declarations.

Ok to commit once all tests completed (still need to
check pre-c++11) ?



The declaration in include/bits/stl_algobase.h has a
noexcept-specifier but the definition in
include/debug/safe_iterator.tcc does not have one - that
seems wrong (I'm surprised it even compiles).


It does !


The diagnostic is suppressed without -Wsystem-headers:


/home/jwakely/gcc/14/include/c++/14.0.1/debug/safe_iterator.tcc:255:5:warning:
declaration of 'template constexpr
decltype (std::__
niter_base(declval<_Ite>())) std::__niter_base(const
__gnu_debug::_Safe_iterator<_Iterator, _Sequence,
random_access_iterator_tag>&)' has a different except
ion specifier [-Wsystem-headers]
 255 | __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
 | ^~~~
/home/jwakely/gcc/14/include/c++/14.0.1/bits/stl_algobase.h:335:5:note:
from previous declaration 'template
constexpr decltype (std
::__niter_base(declval<_Ite>())) std::__niter_base(const
__gnu_debug::_Safe_iterator<_Iterator, _Sequence,
random_access_iterator_tag>&) noexcept (noexcept
(is_nothrow_copy_constructible()))>::value))'
 335 | __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
 | ^~~~


It's a hard error with Clang though:

deb.cc:7:10: error: call to '__niter_base' is ambiguous



Yes, I eventually got the error too, I hadn't run enough tests yet.





I thought it was only necessary at declaration, and I also
had troubles doing it right at definition because of the
interaction with the auto and ->.


The trailing-return-type has to come after the noexcept-specifier.

Now simplified and consistent in this new proposal.



Just using std::is_nothrow_copy_constructible<_Ite> seems
simpler, that will be true for __normal_iterator if
is_nothrow_copy_constructible is true.


Ok



The definition in include/debug/safe_iterator.tcc should use
std::declval<_Ite>() not declval<_Ite>(). Is there any
reason why the definition uses a late-specified-return-type
(i.e. auto and ->) when the declaration doesn't?



I initially plan to use '->
std::decltype(std::__niter_base(__it.base()))' but this did
not compile, ambiguity issue. So I resort to using
std::declval and I could have then done it the same way as
declaration, done now.

Attached is what I'm testing, ok to commit once fully tested ?


OK, thanks.


Thanks for validation but I have a problem to test for c++98.

When I do:

make CXXFLAGS=-std=c++98 check-debug


That doesn't work any more, see 
https://gcc.gnu.org/onlinedocs/libstdc++/manual/test.html#test.run.permutations


I see in debug/libstdc++.log for example:

Executing on host: /home/fdumont/dev/gcc/build/./gcc/xg++
-shared-libgcc ... -mshstk -std=c++98 -g -O2 -DLOCALEDIR="."
-nostdinc++ -I/home/fdumont/dev/gcc/...
/home/fdumont/dev/gcc/git/libstdc++-v3/testsuite/25_algorithms/copy/3.cc
-D_GLIBCXX_DEBUG   -std=gnu++17  -include bits/stdc++.h ...  -lm 
-o ./3.exe    (timeout = 360)

The -std=c++98 is there but later comes the -std=gnu++17 so I
think it runs in C++17, no ?

I also tried the documented alternative:

make check 
'RUNTESTFLAGS=--target_board=unix/-O3\"{-std=gnu++98,-std=gnu++11,-std=gnu++14}\"'

but same problem, -std=gnu++17 comes last.

I'll try to rebuild all from scratch but I won't commit soon then.



Re: [PATCH 5/5][_Hashtable] Prefer to insert after last node

2023-12-19 Thread François Dumont

Here is a new version of this patch.

The previous one had some flaws that were unnoticed by testsuite tests, 
only the performance tests were spotting it. So I'm adding checks on the 
consistency of the unordered containers in this patch.


I also forget to signal that after this patch gnu versioned namespace 
version is supposed to be bump. But I hope it's already the plan because 
of the move to the cxx11 abi in this mode.


Note for reviewer, after application of the patch, a 'git diff -b' is 
much more readable.


And some benches results:

before:

unordered_set_range_insert.cc-thread    hash code NOT cached 2 X 100 
inserts individually 1990 calls      44r   44u    0s 95999760mem    0pf
unordered_set_range_insert.cc-thread    hash code NOT cached 2 X 100 
inserts in range 2000 calls      43r   43u    0s 95999760mem    0pf
unordered_set_range_insert.cc-thread    hash code NOT cached 100 X 
inserts individually 1990 calls      44r   44u 0s  95999760mem    0pf
unordered_set_range_insert.cc-thread    hash code NOT cached 100 X 
inserts in range 2000 calls      43r   43u    0s 95999760mem    0pf
unordered_set_range_insert.cc-thread    hash code cached 2 X 100 
inserts individually 1000 calls      30r   30u    0s 111999328mem    
0pf
unordered_set_range_insert.cc-thread    hash code cached 2 X 100 
inserts in range 1010 calls      33r   32u    0s 111999328mem    0pf
unordered_set_range_insert.cc-thread    hash code cached 100 X 
inserts individually 1000 calls      30r   31u    0s 111999328mem    
0pf
unordered_set_range_insert.cc-thread    hash code cached 100 X 
inserts in range 1010 calls      32r   32u    0s 111999328mem    0pf


after:

unordered_set_range_insert.cc-thread    hash code NOT cached 2 X 100 
inserts individually 1990 calls      44r   44u    0s 95999760mem    0pf
unordered_set_range_insert.cc-thread    hash code NOT cached 2 X 100 
inserts in range 1020 calls      26r   25u    0s 95999760mem    0pf
unordered_set_range_insert.cc-thread    hash code NOT cached 100 X 
inserts individually 1990 calls      43r   44u 0s  95999760mem    0pf
unordered_set_range_insert.cc-thread    hash code NOT cached 100 X 
inserts in range 1020 calls      26r   26u    0s 95999760mem    0pf
unordered_set_range_insert.cc-thread    hash code cached 2 X 100 
inserts individually 1000 calls      35r   35u    0s 111999328mem    
0pf
unordered_set_range_insert.cc-thread    hash code cached 2 X 100 
inserts in range 1010 calls      32r   33u    0s 111999328mem    0pf
unordered_set_range_insert.cc-thread    hash code cached 100 X 
inserts individually 1000 calls      31r   32u    0s 111999328mem    
0pf
unordered_set_range_insert.cc-thread    hash code cached 100 X 
inserts in range 1010 calls      31r   31u    0s 111999328mem    0pf



    libstdc++: [_Hashtable] Prefer to insert after last node

    When inserting an element into an empty bucket we currently insert 
the new node
    after the before-begin node so in first position. The drawback of 
doing this is
    that we are forced to update the bucket that was containing this 
before-begin
    node to point to the newly inserted node. To do so we need at best 
to do a modulo
    to find this bucket and at worst, when hash code is not cached, 
also compute it.


    To avoid this side effect it is better to insert after the last 
node. To do so
    we are introducing a helper type _HintPolicy that has 3 
resposibilities.


    1. When the gnu versioned namespace is used we add a _M_last member 
to _Hashtable,
    _HintPolicy is then in charge of maintaining it. For this purpose 
_HintPolicy is
    using the RAII pattern, it resets the _M_last at destruction level. 
It also maintain

    its own _M_last, all mutable operations are updating it when needed.

    2. When the gnu versioned namespace is not used _HintPolicy will 
still maintain its
    _M_last member using initially the user provided hint if any and if 
it is actually
    the container last node that is to say a dereferenceable node with 
its next node being
    null. All mutable operations can also update the contextual 
_HintPolicy instance

    whenever they detect the last node during their process.

    3. As long as we haven't been able to detect the container last 
node, _HintPolicy
    is used to keep a cache of the before-begin bucket index so that we 
do not need to

    compute it afterward for example in the context of range insertion.

    libstdc++-v3/ChangeLog:

    * include/bits/hashtable.h
[_GLIBCXX_INLINE_VERSION](_Hashtable<>::_M_last): New, the container 
last node.

    (_Hashtable<>::_LastNodeManager): New.
    (_Hashtable<>::_M_get_last(__node_ptr)): New.
(_Hashtable<>::_M_get_last_node_mgr(__node_ptr)): New.
(_Hashtable<>::_M_check_for_last(__node_base_ptr)): New.
    (_Hashtable<>::_M_set_last(__node_ptr)): New.
   

Re: [PATCH] Reimplement __gnu_cxx::__ops operators

2023-12-09 Thread François Dumont



On 07/12/2023 14:41, Jonathan Wakely wrote:

On Wed, 6 Dec 2023 at 20:55, François Dumont  wrote:

I think I still got no feedback about this cleanup proposal.

Can you remind me why we have all those different functions in
predefined_ops.h in the first place? I think it was to avoid having
two versions of every algorithm, one that does *l < *r and one that
does pred(*l, *r), right?

Yes, that was the purpose.


One property of the current code is that _Iter_less_iter will compare
exactly *lhs < *rhs and so works even with this type, where its
operator< only accepts non-const arguments:

struct X { bool operator<(X&); };

Doesn't your simplification break that, because the _Less function
only accepts const references now?


Indeed, I thought more about the problem of const qualification on the 
operator(). This is why _Comp_val is mimicking what _Not_fn does.


To be honnest I even thought that this kind of operator above was more a 
user code issue than a real use case we need to handle. But it looks 
like you, I guess the C++ Standard then, impose to support it.


I'll rework it then, thanks for the proposal below and in your other email.




Re: [PATCH 5/5][_Hashtable] Prefer to insert after last node

2024-01-02 Thread François Dumont



On 21/12/2023 22:55, Jonathan Wakely wrote:

I think this should wait for the next stage 1. It's a big patch
affecting the default -std mode (not just experimental C++20/23/26
material), and was first posted after the end of stage 1.
The idea of this patch was in the air far before it but I agree that its 
form has changed a lot.


Do we really need the changes for versioned namespace? How much
difference does that extra member make to performance, compared with
the version for the default config?


It is huge and demonstrated by the bench results below. You can see that 
the number of calls to the hash functor is divided by 2. With such a 
member you only need to compute 1 hash code when inserting in an empty 
bucket (the perfect hasher case) whereas we currently need 2 to properly 
maintained the bucket pointing to the before-begin base node.


This is also why I proposed it now as I still hope that the patch to 
move to cxx11 abi in gnu versioned namespace will be integrated so with 
its implied version bump.





On Wed, 20 Dec 2023 at 06:10, François Dumont  wrote:

Here is a new version of this patch.

The previous one had some flaws that were unnoticed by testsuite tests,
only the performance tests were spotting it. So I'm adding checks on the
consistency of the unordered containers in this patch.

I also forget to signal that after this patch gnu versioned namespace
version is supposed to be bump. But I hope it's already the plan because
of the move to the cxx11 abi in this mode.

Note for reviewer, after application of the patch, a 'git diff -b' is
much more readable.

And some benches results:

before:

unordered_set_range_insert.cc-threadhash code NOT cached 2 X 100
inserts individually 1990 calls  44r   44u0s 95999760mem0pf
unordered_set_range_insert.cc-threadhash code NOT cached 2 X 100
inserts in range 2000 calls  43r   43u0s 95999760mem0pf
unordered_set_range_insert.cc-threadhash code NOT cached 100 X
inserts individually 1990 calls  44r   44u 0s  95999760mem0pf
unordered_set_range_insert.cc-threadhash code NOT cached 100 X
inserts in range 2000 calls  43r   43u0s 95999760mem0pf
unordered_set_range_insert.cc-threadhash code cached 2 X 100
inserts individually 1000 calls  30r   30u0s 111999328mem
0pf
unordered_set_range_insert.cc-threadhash code cached 2 X 100
inserts in range 1010 calls  33r   32u0s 111999328mem0pf
unordered_set_range_insert.cc-threadhash code cached 100 X
inserts individually 1000 calls  30r   31u0s 111999328mem
0pf
unordered_set_range_insert.cc-threadhash code cached 100 X
inserts in range 1010 calls  32r   32u0s 111999328mem0pf

after:

unordered_set_range_insert.cc-threadhash code NOT cached 2 X 100
inserts individually 1990 calls  44r   44u0s 95999760mem0pf
unordered_set_range_insert.cc-threadhash code NOT cached 2 X 100
inserts in range 1020 calls  26r   25u0s 95999760mem0pf
unordered_set_range_insert.cc-threadhash code NOT cached 100 X
inserts individually 1990 calls  43r   44u 0s  95999760mem0pf
unordered_set_range_insert.cc-threadhash code NOT cached 100 X
inserts in range 1020 calls  26r   26u0s 95999760mem0pf
unordered_set_range_insert.cc-threadhash code cached 2 X 100
inserts individually 1000 calls  35r   35u0s 111999328mem
0pf
unordered_set_range_insert.cc-threadhash code cached 2 X 100
inserts in range 1010 calls  32r   33u0s 111999328mem0pf
unordered_set_range_insert.cc-threadhash code cached 100 X
inserts individually 1000 calls  31r   32u0s 111999328mem
0pf
unordered_set_range_insert.cc-threadhash code cached 100 X
inserts in range 1010 calls  31r   31u0s 111999328mem0pf


  libstdc++: [_Hashtable] Prefer to insert after last node

  When inserting an element into an empty bucket we currently insert
the new node
  after the before-begin node so in first position. The drawback of
doing this is
  that we are forced to update the bucket that was containing this
before-begin
  node to point to the newly inserted node. To do so we need at best
to do a modulo
  to find this bucket and at worst, when hash code is not cached,
also compute it.

  To avoid this side effect it is better to insert after the last
node. To do so
  we are introducing a helper type _HintPolicy that has 3
resposibilities.

  1. When the gnu versioned namespace is used we add a _M_last member
to _Hashtable,
  _HintPolicy is then in charge of maintaining it. For this purpose
_HintPolicy is
  using the RAII pattern, it resets the _M_last at destruction level.
It also maintain
  its own _M_last, all mutable operations are updating it when needed.

  2. When the gnu versioned namespace

Re: [PATCH 2/5][_Hashtable] Fix implementation inconsistencies

2024-01-03 Thread François Dumont


On 21/12/2023 23:07, Jonathan Wakely wrote:

On Thu, 23 Nov 2023 at 21:59, François Dumont  wrote:

  libstdc++: [_Hashtable] Fix some implementation inconsistencies

  Get rid of the different usages of the mutable keyword. For
  _Prime_rehash_policy methods are exported from the library, we need to
  keep their const qualifier, so adapt implementation to update
previously
  mutable member.

If anybody ever declares a const _Prime_rehash_policy and then calls
its _M_next_bkt member or _M_need_rehash member they'll get undefined
behaviour, which seems bad. Probably nobody will ever do that, but if
we just leave the mutable member then that problem doesn't exist.

It would be possible to add non-const overlaods of _M_next_bkt and
_M_need_rehash, and then make the const ones do:

return const_cast<_Prime_rehash_policy*>(this)->_M_next_bkt(n);

or even just define the const symbol as an alias of the non-const
symbol, on targets that support that.  That would still be undefined
if somebody uses a const Prime_rehash_policy object somewhere, but it
would mean the definition of the member functions don't contain nasty
surprises, and new code would call the non-const version, which
doesn't use the unsafe const_cast.
Ok, nevermind for this part, I just commented that the 'const' or 
'mutable' in this implementation are just here for abi compatibility reason.



  Remove useless noexcept qualification on _Hashtable _M_bucket_index
overload.
  Fix comment to explain that we need the computation of bucket index
to be
  noexcept to be able to rehash the container when needed. For Standard
  instantiations through std::unordered_xxx containers we already force
  usage of hash code cache when hash functor is not noexcep so it is
guarantied.
  The static_assert purpose in _Hashtable on _M_bucket_index is thus
limited
  to usages of _Hashtable with exotic _Hashtable_traits.

  libstdc++-v3/ChangeLog:

  * include/bits/hashtable_policy.h
(_NodeBuilder<>::_S_build): Remove
  const qualification on _NodeGenerator instance.
(_ReuseOrAllocNode<>::operator()(_Args&&...)): Remove const qualification.
  (_ReuseOrAllocNode<>::_M_nodes): Remove mutable.
  (_Prime_rehash_policy::max_load_factor()): Remove noexcept.

Why?


  (_Prime_rehash_policy::_M_reset()): Remove noexcept.

Why?

Those functions really are noexcept, right? We should remove noexcept
where it's incorrect or misleading, but here it's OK, isn't it? Or am
I forgetting the problem being solved here?


I just try to answer your remarks in:

https://gcc.gnu.org/pipermail/libstdc++/2023-October/057531.html

AFAI understand 'noexcept' purpose is just to implement some 
optimizations in meta-programmation or have static_assert. As all this 
code is an implementation detail and I'm not using those qualifiers and 
as it seems to raise some concerns to you I just preferred to remove those.


Is the compiler behavior changing w/o it ?

diff --git a/libstdc++-v3/include/bits/hashtable.h 
b/libstdc++-v3/include/bits/hashtable.h
index 9441fe1f91c..adf77f25d41 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -48,7 +48,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 using __cache_default
   =  __not_<__and_,
-  // Mandatory to have erase not throwing.
+  // Mandatory for the rehash process.
   __is_nothrow_invocable>>;
 
   // Helper to conditionally delete the default constructor.
@@ -481,7 +481,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template
void
-   _M_assign(_Ht&&, const _NodeGenerator&);
+   _M_assign(_Ht&&, _NodeGenerator&);
 
   void
   _M_move_assign(_Hashtable&&, true_type);
@@ -796,7 +796,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 private:
   // Bucket index computation helpers.
   size_type
-  _M_bucket_index(const __node_value_type& __n) const noexcept
+  _M_bucket_index(const __node_value_type& __n) const
   { return __hash_code_base::_M_bucket_index(__n, _M_bucket_count); }
 
   size_type
@@ -924,7 +924,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template
std::pair
-   _M_insert_unique(_Kt&&, _Arg&&, const _NodeGenerator&);
+   _M_insert_unique(_Kt&&, _Arg&&, _NodeGenerator&);
 
   template
static __conditional_t<
@@ -944,7 +944,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template
std::pair
-   _M_insert_unique_aux(_Arg&& __arg, const _NodeGenerator& __node_gen)
+   _M_insert_unique_aux(_Arg&& __arg, _NodeGenerator& __node_gen)
{
  return _M_insert_unique(
_S_forward_key(_ExtractKey{}(std::forward<_Arg>(__arg))),
@@ -953,7 +953,7 @@ _GLIBCXX_BEGIN_NAMESPACE

Re: [Bug libstdc++/112477] [13/14 Regression] Assignment of value-initialized iterators differs from value-initialization

2024-01-10 Thread François Dumont
libstdc++: [_GLIBCXX_DEBUG] Fix assignment of value-initialized iterator 
[PR112477]


Now that _M_Detach do not reset iterator _M_version value we need to 
reset it when
the iterator is attached to a new sequence. Even if this sequencer is 
null like when
assigning a value-initialized iterator. In this case _M_version shall be 
reset to 0.


libstdc++-v3/ChangeLog:

    PR libstdc++/112477
    * src/c++11/debug.cc
    (_Safe_iterator_base::_M_attach): Reset _M_version to 0 if 
attaching to null

    sequence.
    (_Safe_iterator_base::_M_attach_single): Likewise.
    (_Safe_local_iterator_base::_M_attach): Likewise.
    (_Safe_local_iterator_base::_M_attach_single): Likewise.
    * testsuite/23_containers/map/debug/112477.cc: New test case.

Tested under Linux x64 _GLIBCXX_DEBUG mode.

Ok to commit and backport to gcc 13 ?

François

On 09/01/2024 22:47, fdumont at gcc dot gnu.org wrote:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112477

François Dumont  changed:

What|Removed |Added

Assignee|unassigned at gcc dot gnu.org  |fdumont at gcc dot 
gnu.org

--- Comment #8 from François Dumont  ---
Hi
I'm going to have a look but if you wish to contribute do not hesitate.
Thanks for the report.
diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc
index bb0d0db6679..cb2cbf9d312 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -437,6 +437,8 @@ namespace __gnu_debug
_M_version = _M_sequence->_M_version;
_M_sequence->_M_attach(this, __constant);
   }
+else
+  _M_version = 0;
   }
 
   void
@@ -452,6 +454,8 @@ namespace __gnu_debug
_M_version = _M_sequence->_M_version;
_M_sequence->_M_attach_single(this, __constant);
   }
+else
+  _M_version = 0;
   }
 
   void
@@ -528,6 +532,8 @@ namespace __gnu_debug
_M_version = _M_sequence->_M_version;
_M_get_container()->_M_attach_local(this, __constant);
   }
+else
+  _M_version = 0;
   }
 
   void
@@ -543,6 +549,8 @@ namespace __gnu_debug
_M_version = _M_sequence->_M_version;
_M_get_container()->_M_attach_local_single(this, __constant);
   }
+else
+  _M_version = 0;
   }
 
   void
diff --git a/libstdc++-v3/testsuite/23_containers/map/debug/112477.cc 
b/libstdc++-v3/testsuite/23_containers/map/debug/112477.cc
new file mode 100644
index 000..bde613b8905
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/map/debug/112477.cc
@@ -0,0 +1,20 @@
+// { dg-do run { target c++11 } }
+// { dg-require-debug-mode "" }
+
+// PR libstdc++/112477
+
+#include 
+
+int main()
+{
+  using M = std::map;
+  using I = M::iterator;
+
+  M map{ {1, 1}, {2, 2} };
+
+  I it1 = map.begin();
+  it1 = I{};
+
+  I it2{};
+  (void)(it1 == it2);
+}


Re: [PATCH] libstdc++: hashtable: No need to update before begin node in _M_remove_bucket_begin

2024-01-17 Thread François Dumont

Hi

Looks like a great finding to me, this is indeed a useless check, thanks!

Have you any figures on the performance enhancement ? It might help to 
get proper approval as gcc is currently in dev stage 4 that is to say 
only bug fixes normally.


François

On 17/01/2024 09:11, Huanghui Nie wrote:


Hi.

When I implemented a hash table with reference to the C++ STL, I found 
that when the hash table in the C++ STL deletes elements, if the first 
element deleted is the begin element, the before begin node is 
repeatedly assigned. This creates unnecessary performance overhead.



First, let’s see the code implementation:

In _M_remove_bucket_begin, _M_before_begin._M_nxt is assigned when 
&_M_before_begin == _M_buckets[__bkt]. That also means 
_M_buckets[__bkt]->_M_nxt is assigned under some conditions.


_M_remove_bucket_begin is called by _M_erase and _M_extract_node:

 1. Case _M_erase a range: _M_remove_bucket_begin is called in a for
loop when __is_bucket_begin is true. And if __is_bucket_begin is
true and &_M_before_begin == _M_buckets[__bkt], __prev_n must be
&_M_before_begin. __prev_n->_M_nxt is always assigned in _M_erase.
That means _M_before_begin._M_nxt is always assigned, if
_M_remove_bucket_begin is called and &_M_before_begin ==
_M_buckets[__bkt]. So there’s no need to assign
_M_before_begin._M_nxt in _M_remove_bucket_begin.
 2. Other cases: _M_remove_bucket_begin is called when __prev_n ==
_M_buckets[__bkt]. And __prev_n->_M_nxt is always assigned in
_M_erase and _M_before_begin. That means _M_buckets[__bkt]->_M_nxt
is always assigned. So there's no need to assign
_M_buckets[__bkt]->_M_nxt in _M_remove_bucket_begin.

In summary, there’s no need to check &_M_before_begin == 
_M_buckets[__bkt] and assign _M_before_begin._M_nxt in 
_M_remove_bucket_begin.



Then let’s see the responsibility of each method:

The hash table in the C++ STL is composed of hash buckets and a node 
list. The update of the node list is responsible for _M_erase and 
_M_extract_node method. _M_remove_bucket_begin method only needs to 
update the hash buckets. The update of _M_before_begin belongs to the 
update of the node list. So _M_remove_bucket_begin doesn’t need to 
update _M_before_begin.



Existing tests listed below cover this change:

23_containers/unordered_set/allocator/copy.cc

23_containers/unordered_set/allocator/copy_assign.cc

23_containers/unordered_set/allocator/move.cc

23_containers/unordered_set/allocator/move_assign.cc

23_containers/unordered_set/allocator/swap.cc

23_containers/unordered_set/erase/1.cc

23_containers/unordered_set/erase/24061-set.cc

23_containers/unordered_set/modifiers/extract.cc

23_containers/unordered_set/operations/count.cc

23_containers/unordered_set/requirements/exception/basic.cc

23_containers/unordered_map/allocator/copy.cc

23_containers/unordered_map/allocator/copy_assign.cc

23_containers/unordered_map/allocator/move.cc

23_containers/unordered_map/allocator/move_assign.cc

23_containers/unordered_map/allocator/swap.cc

23_containers/unordered_map/erase/1.cc

23_containers/unordered_map/erase/24061-map.cc

23_containers/unordered_map/modifiers/extract.cc

23_containers/unordered_map/modifiers/move_assign.cc

23_containers/unordered_map/operations/count.cc

23_containers/unordered_map/requirements/exception/basic.cc


Regression tested on x86_64-pc-linux-gnu. Is it OK to commit?


---

ChangeLog:


libstdc++: hashtable: No need to update before begin node in 
_M_remove_bucket_begin



2024-01-16Huanghui Nie


gcc/

* libstdc++-v3/include/bits/hashtable.h


---


diff --git a/libstdc++-v3/include/bits/hashtable.h 
b/libstdc++-v3/include/bits/hashtable.h


index b48610036fa..6056639e663 100644

--- a/libstdc++-v3/include/bits/hashtable.h

+++ b/libstdc++-v3/include/bits/hashtable.h

@@ -872,13 +872,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION

      if (!__next_n || __next_bkt != __bkt)

        {

          // Bucket is now empty

-         // First update next bucket if any

+         // Update next bucket if any

          if (__next_n)

            _M_buckets[__next_bkt] = _M_buckets[__bkt];

-         // Second update before begin node if necessary

-         if (&_M_before_begin == _M_buckets[__bkt])

-           _M_before_begin._M_nxt = __next_n;

          _M_buckets[__bkt] = nullptr;

        }

    }



Re: [PATCH] Add __cow_string C string constructor

2024-01-07 Thread François Dumont



On 07/01/2024 21:53, Jonathan Wakely wrote:

On Sun, 7 Jan 2024 at 18:50, François Dumont  wrote:


On 07/01/2024 17:34, Jonathan Wakely wrote:

On Sun, 7 Jan 2024 at 12:57, François Dumont  wrote:

Hi

While working on the patch to use the cxx11 abi in gnu version namespace
mode I got a small problem with this missing constructor. I'm not sure
that the main patch will be integrated in gcc 14 so I think it is better
if I propose this patch independently.

   libstdc++: Add __cow_string constructor from C string

   The __cow_string is instantiated from a C string in
cow-stdexcept.cc. At the moment
   the constructor from std::string is being used with the drawback of
an intermediate
   potential allocation/deallocation and copy. With the C string
constructor we bypass
   all those operations.

But in that file, the std::string is the COW string, which means that
when we construct a std::string and copy it, it's cheap. It's just a
reference count increment/decrement. There should be no additional
allocation or deallocation.

Good remark but AFAI understand in this case std::string is the cxx11
one. I'll take a second look.

Clearly in my gnu version namespace patch it is the cxx11 implementation.

I hope not! The whole point of that type is to always be a COW string,
which it does by storing a COW std::basic_string in the union, but
wrapping it in a class with a different name, __cow_string.

If your patch to use the SSO string in the versioned namespace doesn't
change that file to guarantee that __cow_string is still a
copy-on-write type then the patch is wrong and must be fixed.


Don't worry, __cow_string is indeed wrapping a COW string.

What I meant is that in this constructor in :

__cow_string(const std::string&);

The std::string parameter is the SSO string.

However, as you said, in cow-stdexcept.cc the similar constructor is in 
fact taking a COW string so it has less importance. It's just a ODR issue.


In my gnu version namespace patch however this type is still the SSO 
string in cow-stdexcept.cc so I'll keep it in this context.




Even if so, why do we want to do those additional operations ? Adding
this C string constructor will make sure that no useless operations will
be done.

Yes, we could avoid an atomic increment and decrement, but that type
is only used when throwing an exception so the overhead of allocating
memory and calling __cxa_throw etc. is far higher than an atomic
inc/dec pair.

I was going to say that the new constructor would need to be exported
from the shared lib, but I think the new constructor is only ever used
in these two places, both defined in that same file:

   logic_error::logic_error(const char* __arg)
   : exception(), _M_msg(__arg) { }

   runtime_error::runtime_error(const char* __arg)
   : exception(), _M_msg(__arg) { }

So I think the change is safe, but I don't think it's urgent, and
certainly not needed for the reasons claimed in the patch description.

The ODR violation has no side effect, it confirms your statement, looks 
like the __cow_string(const std::string&) could be removed from .





[PATCH] Add __cow_string C string constructor

2024-01-07 Thread François Dumont

Hi

While working on the patch to use the cxx11 abi in gnu version namespace 
mode I got a small problem with this missing constructor. I'm not sure 
that the main patch will be integrated in gcc 14 so I think it is better 
if I propose this patch independently.


    libstdc++: Add __cow_string constructor from C string

    The __cow_string is instantiated from a C string in 
cow-stdexcept.cc. At the moment
    the constructor from std::string is being used with the drawback of 
an intermediate
    potential allocation/deallocation and copy. With the C string 
constructor we bypass

    all those operations.

    libstdc++-v3/ChangeLog:

    * include/std/stdexcept (__cow_string(const char*)): New 
definition.
    * src/c++11/cow-stdexcept.cc (__cow_string(const char*)): 
New definition and

    declaration.

Tested under Linux x64, ok to commit ?

François

diff --git a/libstdc++-v3/include/std/stdexcept 
b/libstdc++-v3/include/std/stdexcept
index 66c8572d0cd..2e3c9f3bf71 100644
--- a/libstdc++-v3/include/std/stdexcept
+++ b/libstdc++-v3/include/std/stdexcept
@@ -54,6 +54,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 __cow_string();
 __cow_string(const std::string&);
+__cow_string(const char*);
 __cow_string(const char*, size_t);
 __cow_string(const __cow_string&) _GLIBCXX_NOTHROW;
 __cow_string& operator=(const __cow_string&) _GLIBCXX_NOTHROW;
diff --git a/libstdc++-v3/src/c++11/cow-stdexcept.cc 
b/libstdc++-v3/src/c++11/cow-stdexcept.cc
index 8d1cc4605d4..12b189b43b5 100644
--- a/libstdc++-v3/src/c++11/cow-stdexcept.cc
+++ b/libstdc++-v3/src/c++11/cow-stdexcept.cc
@@ -127,6 +127,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 __cow_string();
 __cow_string(const std::string& s);
+__cow_string(const char*);
 __cow_string(const char*, size_t n);
 __cow_string(const __cow_string&) noexcept;
 __cow_string& operator=(const __cow_string&) noexcept;
@@ -139,6 +140,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   __cow_string::__cow_string(const std::string& s) : _M_str(s) { }
 
+  __cow_string::__cow_string(const char* s) : _M_str(s) { }
+
   __cow_string::__cow_string(const char* s, size_t n) : _M_str(s, n) { }
 
   __cow_string::__cow_string(const __cow_string& s) noexcept


Re: [PATCH] Add __cow_string C string constructor

2024-01-07 Thread François Dumont



On 07/01/2024 17:34, Jonathan Wakely wrote:

On Sun, 7 Jan 2024 at 12:57, François Dumont  wrote:

Hi

While working on the patch to use the cxx11 abi in gnu version namespace
mode I got a small problem with this missing constructor. I'm not sure
that the main patch will be integrated in gcc 14 so I think it is better
if I propose this patch independently.

  libstdc++: Add __cow_string constructor from C string

  The __cow_string is instantiated from a C string in
cow-stdexcept.cc. At the moment
  the constructor from std::string is being used with the drawback of
an intermediate
  potential allocation/deallocation and copy. With the C string
constructor we bypass
  all those operations.

But in that file, the std::string is the COW string, which means that
when we construct a std::string and copy it, it's cheap. It's just a
reference count increment/decrement. There should be no additional
allocation or deallocation.


Good remark but AFAI understand in this case std::string is the cxx11 
one. I'll take a second look.


Clearly in my gnu version namespace patch it is the cxx11 implementation.

Even if so, why do we want to do those additional operations ? Adding 
this C string constructor will make sure that no useless operations will 
be done.




Am I missing something?



  libstdc++-v3/ChangeLog:

  * include/std/stdexcept (__cow_string(const char*)): New
definition.
  * src/c++11/cow-stdexcept.cc (__cow_string(const char*)):
New definition and
  declaration.

Tested under Linux x64, ok to commit ?

François



Re: [PATCH 3/5][_Hashtable] Avoid redundant usage of rehash policy

2024-01-03 Thread François Dumont

Here is an updated version.

    libstdc++: [_Hashtable] Avoid redundant usage of rehash policy

    Bypass call to __detail::__distance_fwd and the check if rehash is 
needed when
    instantiating from an iterator range or assigning an 
initializer_list to an

    unordered_multimap or unordered_multiset.

    libstdc++-v3/ChangeLog:

    * include/bits/hashtable.h
    (_Hashtable<>::_M_insert_range(_InputIte, _InputIte, 
_NodeGen&)): New.

(_Hashtable<>::operator=(initializer_list)): Use latter.
    (_Hashtable<>::_Hashtable(_InputIte, _InputIte, size_type, 
const _Hash&, const _Equal&,

    const allocator_type&, false_type)): Use latter.
    * include/bits/hashtable_policy.h
    (_Insert_base<>::_M_insert_range): Rename in...
    (_Insert_base<>::_M_insert): ...this and private.

Ok to commit ?

François


On 21/12/2023 23:17, Jonathan Wakely wrote:

On Thu, 23 Nov 2023 at 21:59, François Dumont  wrote:

  libstdc++: [_Hashtable] Avoid redundant usage of rehash policy

  Bypass call to __detail::__distance_fwd and the check if rehash is
needed when
  assigning an initializer_list to an unordered_multimap or
unordered_multiset.

I find this patch and the description a bit confusing. It would help
if the new _Hashtable::_M_insert_range function had a comment (or a
different name!) explaining how it's different from the existing
_Insert_base::_M_insert_range functions.



  libstdc++-v3/ChangeLog:

  * include/bits/hashtable.h
  (_Hashtable<>::_M_insert_range(_InputIte, _InputIte,
_NodeGen&)): New.
(_Hashtable<>::operator=(initializer_list)): Use latter.
  (_Hashtable<>::_Hashtable(_InputIte, _InputIte, size_type,
const _Hash&, const _Equal&,
  const allocator_type&, false_type)): Use latter.
  * include/bits/hashtable_policy.h
  (_Insert_base<>::_M_insert_range(_InputIte, _InputIte,
true_type)): Use latter.
  (_Insert_base<>::_M_insert_range(_InputIte, _InputIte,
false_type)): Likewise.

Tested under Linux x64

Ok to commit ?

Françoisdiff --git a/libstdc++-v3/include/bits/hashtable.h 
b/libstdc++-v3/include/bits/hashtable.h
index adf77f25d41..aec77c34a58 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -616,7 +616,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (_M_bucket_count < __l_bkt_count)
  rehash(__l_bkt_count);
 
-   this->_M_insert_range(__l.begin(), __l.end(), __roan, __unique_keys{});
+   _M_insert_range(__l.begin(), __l.end(), __roan);
return *this;
   }
 
@@ -989,6 +989,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_insert(const_iterator, _Arg&&,
  _NodeGenerator&, false_type __uks);
 
+  template
+   void
+   _M_insert_range(_InputIterator __first, _InputIterator __last,
+   _NodeGenerator&);
+
   size_type
   _M_erase(true_type __uks, const key_type&);
 
@@ -1304,8 +1309,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  }
 
__alloc_node_gen_t __node_gen(*this);
-   for (; __f != __l; ++__f)
- _M_insert(*__f, __node_gen, __uks);
+   _M_insert_range(__f, __l, __node_gen);
   }
 
   template
+template
+  void
+  _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+_Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
+  _M_insert_range(_InputIterator __first, _InputIterator __last,
+ _NodeGenerator& __node_gen)
+  {
+   for (; __first != __last; ++__first)
+ _M_insert(*__first, __node_gen, __unique_keys{});
+  }
+
   template(this)); }
 
-  template
+private:
+  template
void
-   _M_insert_range(_InputIterator __first, _InputIterator __last,
-   _NodeGetter&, true_type __uks);
+   _M_insert(_InputIterator __first, _InputIterator __last,
+ true_type __uks);
 
-  template
+  template
void
-   _M_insert_range(_InputIterator __first, _InputIterator __last,
-   _NodeGetter&, false_type __uks);
+   _M_insert(_InputIterator __first, _InputIterator __last,
+ false_type __uks);
 
 public:
   using iterator = _Node_iterator<_Value, __constant_iterators::value,
@@ -999,41 +1000,37 @@ namespace __detail
   template
void
insert(_InputIterator __first, _InputIterator __last)
-   {
- __hashtable& __h = _M_conjure_hashtable();
- __node_gen_type __node_gen(__h);
- return _M_insert_range(__first, __last, __node_gen, __unique_keys{});
-   }
+   { _M_insert(__first, __last, __unique_keys{}); }
 };
 
   template
-template
+template
   void
   _Insert_base<_Key, _Valu

[PATCH 0/5][_Hashtable] Optimize insertions

2023-11-23 Thread François Dumont
This is a series of patch to enhance _Hashtable insertion operations 
that I'd like to see in gcc 14. I've already submitted something similar 
a couple of months ago but it is quite a revisited version.


1/5 Is adding benches to show the impact of the different optimizations

2/5 Implementation inconsistencies fixes already submitted individually.

3/5 Avoid redundant rehash check on unordered_multi[map/set]

4/5 Extend the small size optimization to all methods

5/5 Insert node for empty bucket after last rather than before-begin

The last patch of the series will require to bump version namespace but 
it is already plan for the cxx11 abi adoption in this mode.


I still need to run the benches that I've already run previously on this 
new version of the patches.


Successfully tested in normal and gnu-versioned namespace modes.

François



[PATCH 1/5][_Hashtable] Add benches

2023-11-23 Thread François Dumont

libstdc++: [_Hashtable] Enhance/Add performance benches

diff --git a/libstdc++-v3/testsuite/performance/23_containers/insert/54075.cc 
b/libstdc++-v3/testsuite/performance/23_containers/insert/54075.cc
index f8fcce31609..f2d975ecdaf 100644
--- a/libstdc++-v3/testsuite/performance/23_containers/insert/54075.cc
+++ b/libstdc++-v3/testsuite/performance/23_containers/insert/54075.cc
@@ -17,12 +17,14 @@
 
 // { dg-do run { target c++11 } }
 
-#include 
+#include 
 #include 
 #include 
 #include 
 #include 
 
+#include 
+
 #define USE_MY_FOO 1
 
 struct Foo
@@ -71,10 +73,13 @@ struct HashFunction
 };
 
 const int sz = 30;
+const int usz = sz / 2;
 
 template
   void
-  bench(const char* container_desc, const typename _ContType::value_type* foos)
+  bench(const char* container_desc,
+   const typename _ContType::value_type* foos,
+   const typename _ContType::value_type* ufoos)
   {
 using namespace __gnu_test;
 
@@ -106,6 +111,51 @@ template
 ostr << container_desc << nb_loop << " times insertion of "
 << sz << " elements";
 report_performance(__FILE__, ostr.str().c_str(), time, resource);
+
+// Try to lookup for mostly unknown entries.
+start_counters(time, resource);
+
+int fcount = 0;
+for (int j = 0; j != nb_loop; ++j)
+  for (int i = 0; i != usz; ++i)
+   fcount += s.find(ufoos[i]) != s.end() ? 1 : 0;
+
+stop_counters(time, resource);
+ostr.str("");
+ostr << container_desc << nb_loop << " times lookup of "
+<< usz << " elements " << fcount / nb_loop << " found";
+report_performance(__FILE__, ostr.str().c_str(), time, resource);
+
+// Try again the previous operations but on a copy with potentially
+// less memory fragmentation.
+_ContType scopy(s);
+
+// Try to insert again to check performance of collision detection
+start_counters(time, resource);
+
+for (int j = 0; j != nb_loop; ++j)
+  for (int i = 0; i != sz; ++i)
+   scopy.insert(foos[i]);
+
+stop_counters(time, resource);
+ostr.str("");
+ostr << container_desc << nb_loop << " times insertion of "
+<< sz << " elements in copy";
+report_performance(__FILE__, ostr.str().c_str(), time, resource);
+
+// Try to lookup for mostly unknown entries.
+start_counters(time, resource);
+
+fcount = 0;
+for (int j = 0; j != nb_loop; ++j)
+  for (int i = 0; i != usz; ++i)
+   fcount += scopy.find(ufoos[i]) != scopy.end() ? 1 : 0;
+
+stop_counters(time, resource);
+ostr.str("");
+ostr << container_desc << nb_loop << " times lookup of "
+<< usz << " elements " << fcount / nb_loop << " found";
+report_performance(__FILE__, ostr.str().c_str(), time, resource);
   }
 
 template
@@ -155,67 +205,78 @@ int main()
 
   {
 int bars[sz];
+int ubars[usz];
 for (int i = 0; i != sz; ++i)
   bars[i] = i;
+for (int i = 0; i != usz; ++i)
+  ubars[i] = sz + i;
 bench>(
-   "std::tr1::unordered_set ", bars);
+  "std::tr1::unordered_set ", bars, ubars);
 bench>(
-   "std::unordered_set ", bars);
+  "std::unordered_set ", bars, ubars);
   }
 
-  Foo foos[sz];
-#if USE_MY_FOO
   {
-std::random_device randev;
-for (int i = 0; i != sz; ++i)
-  foos[i].init(randev);
-  }
+Foo foos[sz];
+Foo ufoos[usz];
+#if USE_MY_FOO
+{
+  std::random_device randev;
+  for (int i = 0; i != sz; ++i)
+   foos[i].init(randev);
+  for (int i = 0; i != usz; ++i)
+   ufoos[i].init(randev);
+}
 #endif
 
-  time_counter time;
-  resource_counter resource;
-  start_counters(time, resource);
-
-  bench<__tr1_uset>(
-   "std::tr1::unordered_set without hash code cached ", foos);
-  bench<__tr1_uset>(
-   "std::tr1::unordered_set with hash code cached ", foos);
-  bench<__tr1_umset>(
-   "std::tr1::unordered_multiset without hash code cached ", foos);
-  bench<__tr1_umset>(
-   "std::tr1::unordered_multiset with hash code cached ", foos);
-
-  stop_counters(time, resource);
-  report_performance(__FILE__, "tr1 benches", time, resource);
-
-  start_counters(time, resource);
-  bench<__uset>(
-   "std::unordered_set without hash code cached ", foos);
-  bench<__uset>(
-   "std::unordered_set with hash code cached ", foos);
-  bench<__umset>(
-   "std::unordered_multiset without hash code cached ", foos);
-  bench<__umset>(
-   "std::unordered_multiset with hash code cached ", foos);
-
-  stop_counters(time, resource);
-  report_performance(__FILE__, "std benches", time, resource);
-
-  start_counters(time, resource);
-  bench<__uset2>(
-   "std::unordered_set2 without hash code cached ", foos);
-  bench<__uset2>(
-   "std::unordered_set2 with hash code cached ", foos);
-  bench<__umset2>(
-   "std::unordered_multiset2 without hash code cached ", foos);
-  bench<__umset2>(
-   "std::unordered_multiset2 with hash code cached ", foos);
-
-  stop_counters(time, resource);
-  

[PATCH 2/5][_Hashtable] Fix implementation inconsistencies

2023-11-23 Thread François Dumont

    libstdc++: [_Hashtable] Fix some implementation inconsistencies

    Get rid of the different usages of the mutable keyword. For
    _Prime_rehash_policy methods are exported from the library, we need to
    keep their const qualifier, so adapt implementation to update 
previously

    mutable member.

    Remove useless noexcept qualification on _Hashtable _M_bucket_index 
overload.
    Fix comment to explain that we need the computation of bucket index 
to be

    noexcept to be able to rehash the container when needed. For Standard
    instantiations through std::unordered_xxx containers we already force
    usage of hash code cache when hash functor is not noexcep so it is 
guarantied.
    The static_assert purpose in _Hashtable on _M_bucket_index is thus 
limited

    to usages of _Hashtable with exotic _Hashtable_traits.

    libstdc++-v3/ChangeLog:

    * include/bits/hashtable_policy.h 
(_NodeBuilder<>::_S_build): Remove

    const qualification on _NodeGenerator instance.
(_ReuseOrAllocNode<>::operator()(_Args&&...)): Remove const qualification.
    (_ReuseOrAllocNode<>::_M_nodes): Remove mutable.
    (_Prime_rehash_policy::max_load_factor()): Remove noexcept.
    (_Prime_rehash_policy::_M_reset()): Remove noexcept.
    (_Prime_rehash_policy::_M_next_resize): Remove mutable.
    (_Power2_rehash_policy::_M_next_bkt(size_t)): Remove noexcept.
    (_Power2_rehash_policy::_M_bkt_for_elements(size_t)): 
Remove noexcept.

    (_Power2_rehash_policy::_M_neeed_rehash): Remove noexcept.
    (_Power2_rehash_policy::_M_reset): Remove noexcept.
    (_Insert_base<>::_M_insert_range): Remove _NodeGetter const 
qualification.
    (_Hash_code_base<>::_M_bucket_index(const 
_Hash_node_value<>&, size_t)):
    Simplify noexcept declaration, we already static_assert 
that _RangeHash functor

    is noexcept.
    * include/bits/hashtable.h: Rework comments. Remove const 
qualifier on

    _NodeGenerator& arguments.
    (_Hashtable<>::_M_bucket_index(const __node_value_type&)): 
Remove useless

    noexcept qualification.
    * src/c++11/hashtable_c++0x.cc (_Prime_rehash_policy): 
Workaround

    _M_next_resize not being mutable anymore.

Tested under Linux x86_64,

ok to commit ?

François
diff --git a/libstdc++-v3/include/bits/hashtable.h 
b/libstdc++-v3/include/bits/hashtable.h
index 9ff9104a2ab..8329d32e68e 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -48,7 +48,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 using __cache_default
   =  __not_<__and_,
-  // Mandatory to have erase not throwing.
+  // Mandatory for the rehash process.
   __is_nothrow_invocable>>;
 
   // Helper to conditionally delete the default constructor.
@@ -477,7 +477,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template
void
-   _M_assign(_Ht&&, const _NodeGenerator&);
+   _M_assign(_Ht&&, _NodeGenerator&);
 
   void
   _M_move_assign(_Hashtable&&, true_type);
@@ -792,7 +792,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 private:
   // Bucket index computation helpers.
   size_type
-  _M_bucket_index(const __node_value_type& __n) const noexcept
+  _M_bucket_index(const __node_value_type& __n) const
   { return __hash_code_base::_M_bucket_index(__n, _M_bucket_count); }
 
   size_type
@@ -920,7 +920,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template
std::pair
-   _M_insert_unique(_Kt&&, _Arg&&, const _NodeGenerator&);
+   _M_insert_unique(_Kt&&, _Arg&&, _NodeGenerator&);
 
   template
static __conditional_t<
@@ -940,7 +940,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template
std::pair
-   _M_insert_unique_aux(_Arg&& __arg, const _NodeGenerator& __node_gen)
+   _M_insert_unique_aux(_Arg&& __arg, _NodeGenerator& __node_gen)
{
  return _M_insert_unique(
_S_forward_key(_ExtractKey{}(std::forward<_Arg>(__arg))),
@@ -949,7 +949,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template
std::pair
-   _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen,
+   _M_insert(_Arg&& __arg, _NodeGenerator& __node_gen,
  true_type /* __uks */)
{
  using __to_value
@@ -960,7 +960,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template
iterator
-   _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen,
+   _M_insert(_Arg&& __arg, _NodeGenerator& __node_gen,
  false_type __uks)
{
  using __to_value
@@ -973,7 +973,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
iterator
_M_insert(const_iterator, _Arg&& __arg,
- const _NodeGenerator& __node_gen, true_type __uks)
+ _NodeGenerator& __node_gen, true_type __uks)
{
   

[PATCH 5/5][_Hashtable] Prefer to insert after last node

2023-11-23 Thread François Dumont

    libstdc++: [_Hashtable] Prefer to insert after last node

    When inserting an element into an empty bucket we currently insert 
the new node
    after the before-begin node so in first position. The drawback of 
doing this is
    that we are forced to update the bucket that was containing this 
before-begin
    node to point to the newly inserted node. To do so we need at best 
to do a modulo
    to find this bucket and at worst, when hash code is not cached, 
also compute it.


    To avoid this side effect it is better to insert after the last 
node. To do so
    we are introducing a helper type _HintPolicy that have 3 
resposibilities.


    1. When the gnu versioned namespace is used we add a _M_last member 
to _Hashtable,
    _HintPolicy is then in charge of maintaining it. For this purpose 
_HintPolicy is
    using the RAII pattern, it resets the _M_last at destruction level. 
It also maintain

    its own _M_last, all mutable operations are updating it when needed.

    2. When the gnu versioned namespace is not used _HintPolicy will 
still maintain its
    _M_last member using initially the user provided hint if any and if 
it is actually
    the container last node that is to say a dereferenceable node with 
its next node being
    null. All mutable operations can also update the contextual 
_HintPolicy instance

    whenever they detect the last node during their process.

    3. As long as we haven't been able to detect the container last 
node _HintPolicy
    is used to keep a cache of the before-begin bucket index so that we 
do not need to

    compute it afterward for example in the context of range insertion.

    libstdc++-v3/ChangeLog:

    * include/bits/hashtable.h
[_GLIBCXX_INLINE_VERSION](_Hashtable<>::_M_last): New, the container 
last node.

    (_Hashtable<>::_HintPolicy): New.
    (_Hashtable<>::_M_get_hint(__node_ptr)): New.
    (_Hashtable<>::_M_get_hint_policy(__node_ptr)): New.
(_Hashtable<>::_M_check_for_last(__node_base_ptr)): New.
    (_Hashtable<>::_M_set_last(__node_ptr)): New.
    (_Hashtable<>::_M_get_last()): New.
    (_Hashtable<>::_M_compute_hash_code(__node_ptr, const 
key_type&)): Remove.

    (_Hashtable<>::_InsertInfo): New struct.
    (_Hashtable<>::_M_get_insert_info): New, return latter.
(_Hashtable<>::operator=(initializer_list<>)): Adapt to instantiate a 
_HintPolicy.
    (_Hashtable<>::_M_insert_bucket_begin): Add _HintPolicy& 
parameter and use it

    to optimize insertion in an empty bucket.
    (_Hashtable<>::_M_insert_unique_node): Add _HintPolicy& 
parameter.
    (_Hashtable<>::_M_insert_multi_node): Likewise and add 
_InsertInfo parameter.

(_Hashtable<>::_M_emplace_unique(_HintPolicy&, _Args&&...)): New.
(_Hashtable<>::_M_emplace_multi(_HintPolicy&, _Args&&...)): New.
    (_Hashtable<>::_M_emplace): Adapt to use latters.
    (_Hashtable<>::_M_insert_unique): Add _HintPolicy& parameter.
    (_Hashtable<>::_M_insert_unique_aux): Add _HintPolicy& 
parameter.

    (_Hashtable<>::_M_insert): Adapt to use latter.
    (_Hashtable<>::emplace_hint(const_iterator, _Args&&...)): 
Adapt.

    (_hashtable<>::rehash(size_type)): Adapt.
    (_Hashtable<>::_M_reinsert_node(const_iterator, node_type&&)):
    Add hint parameter, adapt to use it for _HintPolicy 
instantiation.

    (_Hashtable<>::_M_reinsert_node_multi): Likewise.
    (_Hashtable<>::_M_merge_unique): Adapt.
    (_Hashtable<>::_M_rehash): Add _HintPolicy& parameter.
    (_Hashtable<>::_Hashtable<_InputIte>()): Adapt.
    (_Hashtable<>::_M_assign): Call _M_set_last.
    (_Hashtable<>::_M_reset()): Reset _M_last.
(_Hashtable<>::_M_move_assign(_Hashtable&&, true_type)): Move _M_last.
    (_Hashtable<>(_Hashtable&&, __node_alloc_type&&, 
true_type)): Copy _M_last.
    (_Hashtable<>(_Hashtable&&, __node_alloc_type&&, 
false_type)): Copy _M_last.

    (_Hashtable<>::_M_insert_range): Adapt.
    (_Hashtable<>::_M_erase): Call _M_check_for_last.
    (_Hashtable<>::erase): Likewise.
    * include/bits/hashtable_policy.h:
    (_Map_base<>::operator[](const key_type&)): Use hint policy.
    (_Map_base<>::operator[](key_type&&)): Likewise.
    (_Insert_base<>::insert(const_iterator, const 
value_type&)): Likewise using hint.

    (_Insert_base<>::try_emplace): Likewise.
(_Insert_base<>::_M_insert_range<>(_InputIte, _InputIte, true_type)): 
Use hint policy.
(_Insert_base<>::_M_insert_range<>(_InputIte, _InputIte, false_type)): 
Use hint policy.

    (_Insert<>::insert(const_iterator, value_type&&)): Likewise.
    * include/bits/unordered_map.h 
(unordered_map<>::insert(node_type&&)): Pass cend as

    hint.
    (unordered_map<>::insert(const_iterator, node_type&&)): 
Adapt to use hint.

[PATCH 4/5][_Hashtable] Generalize the small size optimization

2023-11-23 Thread François Dumont

    libstdc++: [_Hashtable] Extend the small size optimization

    A number of methods were still not using the small size 
optimization which
    is to prefer an O(N) research to a hash computation as long as N is 
small.


    libstdc++-v3/ChangeLog:

    * include/bits/hashtable.h: Move comment about all 
equivalent values

    being next to each other in the class documentation header.
    (_M_reinsert_node, _M_merge_unique): Implement small size 
optimization.

    (_M_find_tr, _M_count_tr, _M_equal_range_tr): Likewise.

Tested under Linux x64

Ok to commit ?

François
diff --git a/libstdc++-v3/include/bits/hashtable.h 
b/libstdc++-v3/include/bits/hashtable.h
index 771ed9968f7..aec77c34a58 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -152,6 +152,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*  _M_before_begin, if any, is updated to point to its new before
*  begin node.
*
+   *  Note that all equivalent values, if any, are next to each other, if
+   *  we find a non-equivalent value after an equivalent one it means that
+   *  we won't find any new equivalent value.
+   *
*  On erase, the simple iterator design requires using the hash
*  functor to get the index of the bucket to update. For this
*  reason, when __cache_hash_code is set to false the hash functor must
@@ -1054,10 +1058,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  {
__glibcxx_assert(get_allocator() == __nh.get_allocator());
 
+   __node_ptr __n = nullptr;
const key_type& __k = __nh._M_key();
-   __hash_code __code = this->_M_hash_code(__k);
-   size_type __bkt = _M_bucket_index(__code);
-   if (__node_ptr __n = _M_find_node(__bkt, __k, __code))
+   const size_type __size = size();
+   if (__size <= __small_size_threshold())
+ {
+   for (__n = _M_begin(); __n; __n = __n->_M_next())
+ if (this->_M_key_equals(__k, *__n))
+   break;
+ }
+
+   __hash_code __code;
+   size_type __bkt;
+   if (!__n)
+ {
+   __code = this->_M_hash_code(__k);
+   __bkt = _M_bucket_index(__code);
+   if (__size > __small_size_threshold())
+ __n = _M_find_node(__bkt, __k, __code);
+ }
+
+   if (__n)
  {
__ret.node = std::move(__nh);
__ret.position = iterator(__n);
@@ -1161,11 +1182,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  for (auto __i = __src.cbegin(), __end = __src.cend(); __i != __end;)
{
  auto __pos = __i++;
+ const size_type __size = size();
  const key_type& __k = _ExtractKey{}(*__pos);
+ if (__size <= __small_size_threshold())
+   {
+ bool __found = false;
+ for (auto __n = _M_begin(); __n; __n = __n->_M_next())
+   if (this->_M_key_equals(__k, *__n))
+ {
+   __found = true;
+   break;
+ }
+
+ if (__found)
+   {
+ if (__n_elt != 1)
+   --__n_elt;
+ continue;
+   }
+   }
+
  __hash_code __code
= _M_src_hash_code(__src.hash_function(), __k, *__pos._M_cur);
  size_type __bkt = _M_bucket_index(__code);
- if (_M_find_node(__bkt, __k, __code) == nullptr)
+ if (__size <= __small_size_threshold()
+ || _M_find_node(__bkt, __k, __code) == nullptr)
{
  auto __nh = __src.extract(__pos);
  _M_insert_unique_node(__bkt, __code, __nh._M_ptr, __n_elt);
@@ -1743,6 +1784,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   _M_find_tr(const _Kt& __k)
   -> iterator
   {
+   if (size() <= __small_size_threshold())
+ {
+   for (auto __n = _M_begin(); __n; __n = __n->_M_next())
+ if (this->_M_key_equals_tr(__k, *__n))
+   return iterator(__n);
+   return end();
+ }
+
__hash_code __code = this->_M_hash_code_tr(__k);
std::size_t __bkt = _M_bucket_index(__code);
return iterator(_M_find_node_tr(__bkt, __k, __code));
@@ -1759,6 +1808,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   _M_find_tr(const _Kt& __k) const
   -> const_iterator
   {
+   if (size() <= __small_size_threshold())
+ {
+   for (auto __n = _M_begin(); __n; __n = __n->_M_next())
+ if (this->_M_key_equals_tr(__k, *__n))
+   return const_iterator(__n);
+   return end();
+ }
+
__hash_code __code = this->_M_hash_code_tr(__k);
std::size_t __bkt = _M_bucket_index(__code);
return 

<    2   3   4   5   6   7   8   9   10   11   >