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] Reimplement __gnu_cxx::__ops operators

2023-12-07 Thread Jonathan Wakely
On Thu, 7 Dec 2023 at 13: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?
>
> 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?
>
> Maybe another way to remove the number of types in predefined_ops.h
> would be to compose functions from projections. So instead of
> _Iter_less_iter and _Iter_less_val etc. we have:
>
> template
> struct _Less
> {
>   template
> bool operator()(T& l, U& r) const
> { return LProj()(l) < RProj()(r); }
> };
>
> And a set of projections:
>
> struct _Proj_deref {
>   template
> decltype(auto) operator()(T& t) const
> { return *t; }
> };
> struct _Proj_identity {
>   template
> T& operator()(T& t) const
> { return t; }
> };
>
> Then:
>
> using _Iter_less_iter =_Less<_Proj_deref, _Proj_deref>;
> using _Iter_less_val = _Less<_Proj_deref, _Proj_identity>;
>
> The problem here is the use of decltype(auto) which isn't valid in
> C++98. If we didn't have to support C++98 then we could just use
> forwarding refs in_Less::operator()(T&&, U&&) and use perfect
> forwarding everywhere. But we can't.

I suppose we could use typename iterator_traits::reference instead
of decltype(auto), and hope that typedef is actuallyaccurate, and what
dereferencing the iterator gives us.

I do like the idea of simplifying the algos this way, I'm just
concerned that the changes to the ops will break some code that works
today.


>
>
> >
> > Here is a new version.
> >
> > François
> >
> > On 15/06/2023 07:07, François Dumont wrote:
> > > I think we all agree that __gnu_cxx::__ops needed to be reimplemented,
> > > here it is.
> > >
> > > Note that I kept the usage of std::ref in ,  and .
> > >
> > > libstdc++: Reimplement __gnu_cxx::__ops operators
> > >
> > > Replace functors using iterators as input to adopt functors that
> > > are matching the same Standard expectations as the ones imposed on
> > > predicates used in predicates-aware algos. Doing so we need far less
> > > functors. It impose that iterators are dereference at algo level and
> > > not in the functors anymore.
> > >
> > > libstdc++-v3/ChangeLog:
> > >
> > > * include/std/functional (_Not_fn): Move to...
> > > * include/bits/predefined_ops.h: ...here, and expose a
> > > version
> > > in pre-C++14 mode.
> > > (__not_fn): New, use latter.
> > > (_Iter_less_iter, _Iter_less_val, _Val_less_iter,
> > > _Iter_equal_to_iter)
> > > (_Iter_equal_to_val, _Iter_comp_iter, _Iter_comp_val,
> > > _Val_comp_iter)
> > > (_Iter_equals_val, _Iter_equals_iter, _Iter_pred,
> > > _Iter_comp_val)
> > > (_Iter_comp_to_val, _Iter_comp_to_iter, _Iter_negate):
> > > Remove.
> > > (__iter_less_iter, __iter_less_val, __iter_comp_val,
> > > __val_less_iter)
> > > (__val_comp_iter, __iter_equal_to_iter,
> > > __iter_equal_to_val, __iter_comp_iter)
> > > (__val_comp_iter, __iter_equals_val, __iter_comp_iter,
> > > __pred_iter): Remove.
> > > (_Less, _Equal_to, _Equal_to_val, _Comp_val): New.
> > > (__less, __equal_to, __comp_val): New.
> > > * include/bits/stl_algo.h: Adapt all algos to use new
> > > __gnu_cxx::__ops operators.
> > > When possible use std::move to pass predicates between
> > > routines.
> > > * include/bits/stl_algobase.h: Likewise.
> > > * include/bits/stl_heap.h: Likewise.
> > > * include/std/deque: Cleanup usage of __gnu_cxx::__ops
> > > operators.
> > > * include/std/string: Likewise.
> > > * include/std/vector: Likewise.
> > >
> > > Tested under Linux x86_64 normal and _GLIBCXX_DEBUG modes.
> > >
> > > Ok to commit ?
> > >
> > > François
> > >



Re: [PATCH] Reimplement __gnu_cxx::__ops operators

2023-12-07 Thread Jonathan Wakely
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?

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?

Maybe another way to remove the number of types in predefined_ops.h
would be to compose functions from projections. So instead of
_Iter_less_iter and _Iter_less_val etc. we have:

template
struct _Less
{
  template
bool operator()(T& l, U& r) const
{ return LProj()(l) < RProj()(r); }
};

And a set of projections:

struct _Proj_deref {
  template
decltype(auto) operator()(T& t) const
{ return *t; }
};
struct _Proj_identity {
  template
T& operator()(T& t) const
{ return t; }
};

Then:

using _Iter_less_iter =_Less<_Proj_deref, _Proj_deref>;
using _Iter_less_val = _Less<_Proj_deref, _Proj_identity>;

The problem here is the use of decltype(auto) which isn't valid in
C++98. If we didn't have to support C++98 then we could just use
forwarding refs in_Less::operator()(T&&, U&&) and use perfect
forwarding everywhere. But we can't.


>
> Here is a new version.
>
> François
>
> On 15/06/2023 07:07, François Dumont wrote:
> > I think we all agree that __gnu_cxx::__ops needed to be reimplemented,
> > here it is.
> >
> > Note that I kept the usage of std::ref in ,  and .
> >
> > libstdc++: Reimplement __gnu_cxx::__ops operators
> >
> > Replace functors using iterators as input to adopt functors that
> > are matching the same Standard expectations as the ones imposed on
> > predicates used in predicates-aware algos. Doing so we need far less
> > functors. It impose that iterators are dereference at algo level and
> > not in the functors anymore.
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/std/functional (_Not_fn): Move to...
> > * include/bits/predefined_ops.h: ...here, and expose a
> > version
> > in pre-C++14 mode.
> > (__not_fn): New, use latter.
> > (_Iter_less_iter, _Iter_less_val, _Val_less_iter,
> > _Iter_equal_to_iter)
> > (_Iter_equal_to_val, _Iter_comp_iter, _Iter_comp_val,
> > _Val_comp_iter)
> > (_Iter_equals_val, _Iter_equals_iter, _Iter_pred,
> > _Iter_comp_val)
> > (_Iter_comp_to_val, _Iter_comp_to_iter, _Iter_negate):
> > Remove.
> > (__iter_less_iter, __iter_less_val, __iter_comp_val,
> > __val_less_iter)
> > (__val_comp_iter, __iter_equal_to_iter,
> > __iter_equal_to_val, __iter_comp_iter)
> > (__val_comp_iter, __iter_equals_val, __iter_comp_iter,
> > __pred_iter): Remove.
> > (_Less, _Equal_to, _Equal_to_val, _Comp_val): New.
> > (__less, __equal_to, __comp_val): New.
> > * include/bits/stl_algo.h: Adapt all algos to use new
> > __gnu_cxx::__ops operators.
> > When possible use std::move to pass predicates between
> > routines.
> > * include/bits/stl_algobase.h: Likewise.
> > * include/bits/stl_heap.h: Likewise.
> > * include/std/deque: Cleanup usage of __gnu_cxx::__ops
> > operators.
> > * include/std/string: Likewise.
> > * include/std/vector: Likewise.
> >
> > Tested under Linux x86_64 normal and _GLIBCXX_DEBUG modes.
> >
> > Ok to commit ?
> >
> > François
> >



Re: [PATCH] Reimplement __gnu_cxx::__ops operators

2023-12-06 Thread François Dumont

I think I still got no feedback about this cleanup proposal.

Here is a new version.

François

On 15/06/2023 07:07, François Dumont wrote:
I think we all agree that __gnu_cxx::__ops needed to be reimplemented, 
here it is.


Note that I kept the usage of std::ref in ,  and .

    libstdc++: Reimplement __gnu_cxx::__ops operators

    Replace functors using iterators as input to adopt functors that
    are matching the same Standard expectations as the ones imposed on
    predicates used in predicates-aware algos. Doing so we need far less
    functors. It impose that iterators are dereference at algo level and
    not in the functors anymore.

    libstdc++-v3/ChangeLog:

    * include/std/functional (_Not_fn): Move to...
    * include/bits/predefined_ops.h: ...here, and expose a 
version

    in pre-C++14 mode.
    (__not_fn): New, use latter.
    (_Iter_less_iter, _Iter_less_val, _Val_less_iter, 
_Iter_equal_to_iter)
    (_Iter_equal_to_val, _Iter_comp_iter, _Iter_comp_val, 
_Val_comp_iter)
    (_Iter_equals_val, _Iter_equals_iter, _Iter_pred, 
_Iter_comp_val)
    (_Iter_comp_to_val, _Iter_comp_to_iter, _Iter_negate): 
Remove.
    (__iter_less_iter, __iter_less_val, __iter_comp_val, 
__val_less_iter)
    (__val_comp_iter, __iter_equal_to_iter, 
__iter_equal_to_val, __iter_comp_iter)
    (__val_comp_iter, __iter_equals_val, __iter_comp_iter, 
__pred_iter): Remove.

    (_Less, _Equal_to, _Equal_to_val, _Comp_val): New.
    (__less, __equal_to, __comp_val): New.
    * include/bits/stl_algo.h: Adapt all algos to use new 
__gnu_cxx::__ops operators.
    When possible use std::move to pass predicates between 
routines.

    * include/bits/stl_algobase.h: Likewise.
    * include/bits/stl_heap.h: Likewise.
    * include/std/deque: Cleanup usage of __gnu_cxx::__ops 
operators.

    * include/std/string: Likewise.
    * include/std/vector: Likewise.

Tested under Linux x86_64 normal and _GLIBCXX_DEBUG modes.

Ok to commit ?

François
diff --git a/libstdc++-v3/include/bits/predefined_ops.h 
b/libstdc++-v3/include/bits/predefined_ops.h
index e9933373ed9..8753e6f64cd 100644
--- a/libstdc++-v3/include/bits/predefined_ops.h
+++ b/libstdc++-v3/include/bits/predefined_ops.h
@@ -32,376 +32,229 @@
 
 #include 
 
+#if __cplusplus >= 201103L
+# include 
+#endif
+
 namespace __gnu_cxx
 {
 namespace __ops
 {
-  struct _Iter_less_iter
+  struct _Less
   {
-template
+template
   _GLIBCXX14_CONSTEXPR
   bool
-  operator()(_Iterator1 __it1, _Iterator2 __it2) const
-  { return *__it1 < *__it2; }
+  operator()(const _Lhs& __lhs, const _Rhs& __rhs) const
+  { return __lhs < __rhs; }
   };
 
   _GLIBCXX14_CONSTEXPR
-  inline _Iter_less_iter
-  __iter_less_iter()
-  { return _Iter_less_iter(); }
-
-  struct _Iter_less_val
-  {
-#if __cplusplus >= 201103L
-constexpr _Iter_less_val() = default;
-#else
-_Iter_less_val() { }
-#endif
-
-_GLIBCXX20_CONSTEXPR
-explicit
-_Iter_less_val(_Iter_less_iter) { }
-
-template
-  _GLIBCXX20_CONSTEXPR
-  bool
-  operator()(_Iterator __it, _Value& __val) const
-  { return *__it < __val; }
-  };
-
-  _GLIBCXX20_CONSTEXPR
-  inline _Iter_less_val
-  __iter_less_val()
-  { return _Iter_less_val(); }
-
-  _GLIBCXX20_CONSTEXPR
-  inline _Iter_less_val
-  __iter_comp_val(_Iter_less_iter)
-  { return _Iter_less_val(); }
-
-  struct _Val_less_iter
-  {
-#if __cplusplus >= 201103L
-constexpr _Val_less_iter() = default;
-#else
-_Val_less_iter() { }
-#endif
-
-_GLIBCXX20_CONSTEXPR
-explicit
-_Val_less_iter(_Iter_less_iter) { }
-
-template
-  _GLIBCXX20_CONSTEXPR
-  bool
-  operator()(_Value& __val, _Iterator __it) const
-  { return __val < *__it; }
-  };
+  inline _Less
+  __less()
+  { return _Less(); }
 
-  _GLIBCXX20_CONSTEXPR
-  inline _Val_less_iter
-  __val_less_iter()
-  { return _Val_less_iter(); }
-
-  _GLIBCXX20_CONSTEXPR
-  inline _Val_less_iter
-  __val_comp_iter(_Iter_less_iter)
-  { return _Val_less_iter(); }
-
-  struct _Iter_equal_to_iter
+  struct _Equal_to
   {
-template
+template
   _GLIBCXX20_CONSTEXPR
   bool
-  operator()(_Iterator1 __it1, _Iterator2 __it2) const
-  { return *__it1 == *__it2; }
+  operator()(const _Lhs& __lhs, const _Rhs& __rhs) const
+  { return __lhs == __rhs; }
   };
 
   _GLIBCXX20_CONSTEXPR
-  inline _Iter_equal_to_iter
-  __iter_equal_to_iter()
-  { return _Iter_equal_to_iter(); }
-
-  struct _Iter_equal_to_val
-  {
-template
-  _GLIBCXX20_CONSTEXPR
-  bool
-  operator()(_Iterator __it, _Value& __val) const
-  { return *__it == __val; }
-  };
+  inline _Equal_to
+  __equal_to()
+  { return _Equal_to(); }
 
-  _GLIBCXX20_CONSTEXPR
-  inline _Iter_equal_to_val
-  __iter_equal_to_val()
-  { return _Iter_equal_to_val(); }
-
-  _GLIBCXX20_CONSTEXPR
-  

[PATCH] Reimplement __gnu_cxx::__ops operators

2023-06-14 Thread François Dumont via Gcc-patches
I think we all agree that __gnu_cxx::__ops needed to be reimplemented, 
here it is.


Note that I kept the usage of std::ref in ,  and .

    libstdc++: Reimplement __gnu_cxx::__ops operators

    Replace functors using iterators as input to adopt functors that
    are matching the same Standard expectations as the ones imposed on
    predicates used in predicates-aware algos. Doing so we need far less
    functors. It impose that iterators are dereference at algo level and
    not in the functors anymore.

    libstdc++-v3/ChangeLog:

    * include/std/functional (_Not_fn): Move to...
    * include/bits/predefined_ops.h: ...here, and expose a version
    in pre-C++14 mode.
    (__not_fn): New, use latter.
    (_Iter_less_iter, _Iter_less_val, _Val_less_iter, 
_Iter_equal_to_iter)
    (_Iter_equal_to_val, _Iter_comp_iter, _Iter_comp_val, 
_Val_comp_iter)
    (_Iter_equals_val, _Iter_equals_iter, _Iter_pred, 
_Iter_comp_val)

    (_Iter_comp_to_val, _Iter_comp_to_iter, _Iter_negate): Remove.
    (__iter_less_iter, __iter_less_val, __iter_comp_val, 
__val_less_iter)
    (__val_comp_iter, __iter_equal_to_iter, 
__iter_equal_to_val, __iter_comp_iter)
    (__val_comp_iter, __iter_equals_val, __iter_comp_iter, 
__pred_iter): Remove.

    (_Less, _Equal_to, _Equal_to_val, _Comp_val): New.
    (__less, __equal_to, __comp_val): New.
    * include/bits/stl_algo.h: Adapt all algos to use new 
__gnu_cxx::__ops operators.
    When possible use std::move to pass predicates between 
routines.

    * include/bits/stl_algobase.h: Likewise.
    * include/bits/stl_heap.h: Likewise.
    * include/std/deque: Cleanup usage of __gnu_cxx::__ops 
operators.

    * include/std/string: Likewise.
    * include/std/vector: Likewise.

Tested under Linux x86_64 normal and _GLIBCXX_DEBUG modes.

Ok to commit ?

François

diff --git a/libstdc++-v3/include/bits/predefined_ops.h b/libstdc++-v3/include/bits/predefined_ops.h
index e9933373ed9..dc8920ed5f8 100644
--- a/libstdc++-v3/include/bits/predefined_ops.h
+++ b/libstdc++-v3/include/bits/predefined_ops.h
@@ -32,376 +32,170 @@
 
 #include 
 
+#if __cplusplus >= 201103L
+# include 
+#endif
+
 namespace __gnu_cxx
 {
 namespace __ops
 {
-  struct _Iter_less_iter
+  struct _Less
   {
-template
+template
   _GLIBCXX14_CONSTEXPR
   bool
-  operator()(_Iterator1 __it1, _Iterator2 __it2) const
-  { return *__it1 < *__it2; }
+  operator()(const _Lhs& __lhs, const _Rhs& __rhs) const
+  { return __lhs < __rhs; }
   };
 
   _GLIBCXX14_CONSTEXPR
-  inline _Iter_less_iter
-  __iter_less_iter()
-  { return _Iter_less_iter(); }
-
-  struct _Iter_less_val
-  {
-#if __cplusplus >= 201103L
-constexpr _Iter_less_val() = default;
-#else
-_Iter_less_val() { }
-#endif
-
-_GLIBCXX20_CONSTEXPR
-explicit
-_Iter_less_val(_Iter_less_iter) { }
-
-template
-  _GLIBCXX20_CONSTEXPR
-  bool
-  operator()(_Iterator __it, _Value& __val) const
-  { return *__it < __val; }
-  };
-
-  _GLIBCXX20_CONSTEXPR
-  inline _Iter_less_val
-  __iter_less_val()
-  { return _Iter_less_val(); }
-
-  _GLIBCXX20_CONSTEXPR
-  inline _Iter_less_val
-  __iter_comp_val(_Iter_less_iter)
-  { return _Iter_less_val(); }
-
-  struct _Val_less_iter
-  {
-#if __cplusplus >= 201103L
-constexpr _Val_less_iter() = default;
-#else
-_Val_less_iter() { }
-#endif
-
-_GLIBCXX20_CONSTEXPR
-explicit
-_Val_less_iter(_Iter_less_iter) { }
-
-template
-  _GLIBCXX20_CONSTEXPR
-  bool
-  operator()(_Value& __val, _Iterator __it) const
-  { return __val < *__it; }
-  };
-
-  _GLIBCXX20_CONSTEXPR
-  inline _Val_less_iter
-  __val_less_iter()
-  { return _Val_less_iter(); }
-
-  _GLIBCXX20_CONSTEXPR
-  inline _Val_less_iter
-  __val_comp_iter(_Iter_less_iter)
-  { return _Val_less_iter(); }
-
-  struct _Iter_equal_to_iter
-  {
-template
-  _GLIBCXX20_CONSTEXPR
-  bool
-  operator()(_Iterator1 __it1, _Iterator2 __it2) const
-  { return *__it1 == *__it2; }
-  };
-
-  _GLIBCXX20_CONSTEXPR
-  inline _Iter_equal_to_iter
-  __iter_equal_to_iter()
-  { return _Iter_equal_to_iter(); }
+  inline _Less
+  __less()
+  { return _Less(); }
 
-  struct _Iter_equal_to_val
+  struct _Equal_to
   {
-template
+template
   _GLIBCXX20_CONSTEXPR
   bool
-  operator()(_Iterator __it, _Value& __val) const
-  { return *__it == __val; }
+  operator()(const _Lhs& __lhs, const _Rhs& __rhs) const
+  { return __lhs == __rhs; }
   };
 
   _GLIBCXX20_CONSTEXPR
-  inline _Iter_equal_to_val
-  __iter_equal_to_val()
-  { return _Iter_equal_to_val(); }
-
-  _GLIBCXX20_CONSTEXPR
-  inline _Iter_equal_to_val
-  __iter_comp_val(_Iter_equal_to_iter)
-  { return _Iter_equal_to_val(); }
-
-  template
-struct _Iter_comp_iter
-{
-  _Compare _M_comp;
-
-  explicit