Topic: Generic algorithms?


Author: Nick Mocha <nicmoc@gmail.com>
Date: Wed, 17 Jun 2009 20:11:26 CST
Raw View
Today, my interest was piqued by the problem of reversing the contents
of a sequence container.

[A sequence container maintains elements in sequence (list/vector
like), rather than in order (set/map like), or even unordered (hash)]

Since both list::iterator and vector::iterator are Bidirectional, I
can use:

   std::reverse(listOrVector.begin(), listOrVector.end());

If I know that I have a std::list, I can also use:

   knownAsList.reverse();

But I cannot:

   knownAsVector.reverse();    // vector cannot itself reverse

So I'll use std::reverse in the following generic function, accessing
the optimizations of the standard algorithms and insulating myself
from a change of Container from std::list to std::vector:

   template <typename Container>
   void doReverse(Container& container) {
       std::reverse(container.begin(), container.end());
   }

But then, C++0x introduces the forward_list and forward_list::iterator
is not Bidirectional.  Someone changes the Container from std::list or
std::vector to std::forward_list and then where am I?  std::reverse
can't help me unless I give it Bidirectionals.

std::reverse requires Bidirectional iterators because it swaps the
front with the back, then moves both towards the middle until it meets
itself.  It's O(n).

But I can think of a nice O(n) reverse algorithm for
std::forward_list, in fact, there is a proposed
std::forward_list::reverse that probably does just that algorithm.

In summary:

   list.reverse(); // okay
   std::reverse(list.begin(), list.end()); // okay

   vec.reverse();  // no method
   std::reverse(vec.begin(), vec.end()); // okay

   fwdlist.reverse(); // okay
   std::reverse(fwdlist.begin(), fwdlist.end());  // bad

No generic combination.

C++0x adds new containers and defines those in terms of the new
concept of concepts, but are the algorithms keeping pace with the rest
of the language and the library?

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Mathias Gaunard <loufoque@gmail.com>
Date: Thu, 18 Jun 2009 18:30:41 CST
Raw View
On 18 juin, 04:11, Nick Mocha <nic...@gmail.com> wrote:

> Since both list::iterator and vector::iterator are Bidirectional, I
> can use:
>
>    std::reverse(listOrVector.begin(), listOrVector.end());
>
> If I know that I have a std::list, I can also use:
>
>    knownAsList.reverse();
>
> But I cannot:
>
>    knownAsVector.reverse();    // vector cannot itself reverse

The reason std::list has is own reverse function is because the data
structure allows efficient reversal without accessing the elements.

A better generic reverse would be range-based.

template<typename Range>
typename disable_if<has_reverse<Range>>::type reverse(Range&& r)
{
     std::reverse(begin(r), end(r));
}

template<typename Range>
typename enable_if<has_reverse<Range>>::type reverse(Range& r)
{
     r.reverse();
}

Range-based algorithms may come in TR2.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Nick Mocha <nicmoc@gmail.com>
Date: Sun, 21 Jun 2009 17:07:24 CST
Raw View
> The reason std::list has is own reverse function is because the data
> structure allows efficient reversal without accessing the elements.

Agreed, likewise for std::forward_list.

But note that std::reverse(b,e) cannot be applied to
std::forward_list::iterators.

Note also that there is a possible algorithm for reversing a
std::forward_list through std::forward_list::iterators (with at most
one swap, plus O(e-b) internal relinking in a O(e-b) traversal).

Such an algorithm can (at least) match the std::reverse complexity
requirement, but it can never match the std::reverse requirement for
bidirectional iterators.

The fact that std::reverse precludes its application to
std::forward_list::iterators, on the bidirectional requirement alone,
seems to demonstrate a regression of cohesion within the container/
algorithm framework.

Cohesion existed when all sequence containers were bidirectional in
nature - now that we have a "sequence container" (sic) that is not
bidirectional.

Should we leak cohesion or strengthen the algorithms?

(Reference also std::partition).

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]