forked from boostorg/iterator
did some updating to match the current implementation
[SVN r866]
This commit is contained in:
@@ -114,19 +114,28 @@ traversal:
|
|||||||
Traversal Iterator</A>
|
Traversal Iterator</A>
|
||||||
<LI><A
|
<LI><A
|
||||||
href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept:RandomAccessTraversalIterator">Random
|
href="file:///C:/WINDOWS/TEMP/iterator-categories.html#concept:RandomAccessTraversalIterator">Random
|
||||||
Access Traversal Iterator</A> </LI></UL>The current Input Iterator and Output
|
Access Traversal Iterator</A> </LI>
|
||||||
Iterator requirements will continue to be used as is. Note that Input Iterator
|
</UL>
|
||||||
implies Readable Iterator and Output Iterator implies Writable Iterator.
|
|
||||||
<P>Note: we considered defining a Single-Pass Iterator, which could be combined
|
|
||||||
with Readable or Writable Iterator to replace the Input and Output Iterator
|
|
||||||
requirements. We rejected this idea because there are several differences
|
|
||||||
between Input and Output Iterators that make it hard to merge them: Input
|
|
||||||
Iterator requires Equality Comparable while Output Iterator does not and Input
|
|
||||||
Iterator requires Assignable while Output Iterator does not.
|
|
||||||
<H3>New categories and traits classes</H3>Each of the new iterator requirements
|
|
||||||
will need a category tag. <PRE>namespace std {
|
|
||||||
|
|
||||||
// Return Type Categories
|
<P>The current Input Iterator and Output Iterator requirements will
|
||||||
|
continue to be used as is. Note that Input Iterator implies Readable
|
||||||
|
Iterator and Output Iterator implies Writable Iterator.</P>
|
||||||
|
|
||||||
|
<P>Note: we considered defining a Single-Pass Iterator, which could be
|
||||||
|
combined with Readable or Writable Iterator to replace the Input and
|
||||||
|
Output Iterator requirements. We rejected this idea because there are
|
||||||
|
several differences between Input and Output Iterators that make it
|
||||||
|
hard to merge them: Input Iterator requires Equality Comparable while
|
||||||
|
Output Iterator does not and Input Iterator requires Assignable while
|
||||||
|
Output Iterator does not.</P>
|
||||||
|
|
||||||
|
<H3>New category tags and traits classes</H3>
|
||||||
|
|
||||||
|
<P>The new iterator categories will require new tag classes.</P>
|
||||||
|
|
||||||
|
<PRE>namespace std {
|
||||||
|
|
||||||
|
// Returns Category Tags
|
||||||
struct readable_iterator_tag { };
|
struct readable_iterator_tag { };
|
||||||
struct writable_iterator_tag { };
|
struct writable_iterator_tag { };
|
||||||
struct swappable_iterator_tag { };
|
struct swappable_iterator_tag { };
|
||||||
@@ -134,7 +143,7 @@ will need a category tag. <PRE>namespace std {
|
|||||||
virtual public readable_iterator_tag { };
|
virtual public readable_iterator_tag { };
|
||||||
struct constant_lvalue_iterator_tag : public readable_iterator_tag { };
|
struct constant_lvalue_iterator_tag : public readable_iterator_tag { };
|
||||||
|
|
||||||
// Traversal Categories
|
// Traversal Category Tags
|
||||||
struct input_traversal_tag { };
|
struct input_traversal_tag { };
|
||||||
struct output_traversal_tag { };
|
struct output_traversal_tag { };
|
||||||
struct forward_traversal_tag { };
|
struct forward_traversal_tag { };
|
||||||
@@ -142,41 +151,107 @@ will need a category tag. <PRE>namespace std {
|
|||||||
struct random_access_traversal_tag : public bidirectional_traversal_tag { };
|
struct random_access_traversal_tag : public bidirectional_traversal_tag { };
|
||||||
|
|
||||||
}
|
}
|
||||||
</PRE>And there will need to be a way to access these category tags using a
|
</PRE>
|
||||||
traits mechanism. Adding new typedefs to <TT>std::iterator_traits</TT> is not an
|
|
||||||
acceptable solution because that would break every existing iterator. Instead,
|
|
||||||
we propose two new traits classes. It is important that these traits classes are
|
|
||||||
<B>backward compatible</B>, that is, they should work with any iterator for
|
|
||||||
which there is a valid definition of <TT>std::iterator_traits</TT>. This can be
|
|
||||||
accomplished by making the default behavior of the traits classes map the
|
|
||||||
<TT>iterator_category</TT> of the iterator to the appropriate return or
|
|
||||||
traversal category. For new iterators, either specializations of these traits
|
|
||||||
classes can be defined, or the iterator can provide nested typedefs, and inherit
|
|
||||||
from <TT>new_iterator_base</TT> (which is just a signal to the traits class that
|
|
||||||
it is a new iterator). As with <TT>std::iterator_traits</TT>, specializations
|
|
||||||
for <TT>T*</TT> are provided. <PRE>namespace std {
|
|
||||||
|
|
||||||
struct new_iterator_base { };
|
<P>Access to the return and traversal tags will be through the
|
||||||
|
following two traits classes, which have a member typedef named
|
||||||
|
<TT>type</TT> that provides the tag type. We explain the
|
||||||
|
definitions of these classes later.</P>
|
||||||
|
|
||||||
|
<PRE>
|
||||||
|
template <typename Iterator>
|
||||||
|
struct return_category; // contains: typedef ... type;
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
struct return_category
|
struct traversal_category; // contains: typedef ... type;
|
||||||
|
</PRE>
|
||||||
|
|
||||||
|
<P>We want it to be convenient for programmers to create iterators
|
||||||
|
that satisfy both the old and new iterator requirements. Therefore
|
||||||
|
the following class is provided as a way to create tags for use as the
|
||||||
|
old <TT>iterator_category</TT> typedef within
|
||||||
|
<TT>iterator_traits</TT>.
|
||||||
|
|
||||||
|
<PRE>namespace std {
|
||||||
|
template <class ReturnTag, class TraversalTag>
|
||||||
|
struct iterator_tag : cvt_iterator_category<ReturnTag, TraversalTag>::type
|
||||||
|
{
|
||||||
|
typedef ReturnTag returns;
|
||||||
|
typedef TraversalTag traversal;
|
||||||
|
};
|
||||||
|
</PRE>
|
||||||
|
|
||||||
|
<P>The <TT>cvt_iterator_category</TT> template computes the
|
||||||
|
appropriate old iterator category based on the return and traversal
|
||||||
|
category.</P>
|
||||||
|
|
||||||
|
<PRE>namespace std {
|
||||||
|
template <class RC, class TC>
|
||||||
|
struct cvt_iterator_category
|
||||||
|
{
|
||||||
|
<B><I>// Pseudo-code, <= means inherits or same type</I></B>
|
||||||
|
if (RC <= constant_lvalue_iterator_tag || RC <= mutable_lvalue_iterator_tag) {
|
||||||
|
if (TC <= random_access_traversal_tag)
|
||||||
|
typedef random_access_iterator_tag type;
|
||||||
|
else if (TC <= bidirectional_traversal_tag)
|
||||||
|
typedef bidirectional_iterator_tag type;
|
||||||
|
else if (TC <= forward_traversal_tag)
|
||||||
|
typedef forward_iterator_tag type;
|
||||||
|
else
|
||||||
|
error;
|
||||||
|
} else if (RC <= readable_iterator_tag && RC <= input_traversal_tag)
|
||||||
|
typedef input_iterator_tag type;
|
||||||
|
else if (RC <= writable_iterator_tag && output_traversal_tag)
|
||||||
|
typedef output_iterator_tag type;
|
||||||
|
else
|
||||||
|
error;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</PRE>
|
||||||
|
|
||||||
|
<P>The following is an example of a new iterator class using the
|
||||||
|
<TT>iterator_tag</TT> class to create its <TT>iterator_category</TT>
|
||||||
|
member typedef.</P>
|
||||||
|
|
||||||
|
<PRE>
|
||||||
|
struct my_iterator {
|
||||||
|
typedef std::iterator_tag<std::readable_iterator_tag,
|
||||||
|
std::random_access_traversal_tag> iterator_category;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
</PRE>
|
||||||
|
|
||||||
|
We also want old iterators to work with new algorithms, that is,
|
||||||
|
algorithms that use the new iterator categories. We facilitate this by
|
||||||
|
defining the <TT>return_category</TT> and <TT>traversal_category</TT>
|
||||||
|
in such a way as they can be used with both old and new iterators.
|
||||||
|
For old iterators, the appropriate return and traversal categories are
|
||||||
|
computed based on the old iterator category. For new iterators, the
|
||||||
|
return and traversal tags are extracted from within the
|
||||||
|
<TT>iterator_category</TT> tag.
|
||||||
|
|
||||||
|
|
||||||
|
<PRE>
|
||||||
|
template <typename Iterator>
|
||||||
|
class return_category
|
||||||
{
|
{
|
||||||
<B><I>// Pseudo-code</I></B>
|
<B><I>// Pseudo-code</I></B>
|
||||||
if (Iterator inherits from new_iterator_base) {
|
typedef iterator_traits<Iterator>::iterator_category tag;
|
||||||
typedef typename Iterator::return_category type;
|
typedef iterator_traits<Iterator>::value_type T;
|
||||||
} else {
|
public:
|
||||||
typedef std::iterator_traits<Iterator> OldTraits;
|
if (exists(tag::returns)) // must be a new iterator
|
||||||
typedef typename OldTraits::iterator_category Cat;
|
typedef tag::returns type;
|
||||||
if (Cat inherits from std::forward_iterator_tag)
|
else if (tag <= forward_iterator_tag) {
|
||||||
if (is-const(T))
|
if (is-const(T))
|
||||||
typedef boost::constant_lvalue_iterator_tag type;
|
typedef constant_lvalue_iterator_tag type;
|
||||||
else
|
else
|
||||||
typedef boost::mutable_lvalue_iterator_tag type;
|
typedef mutable_lvalue_iterator_tag type;
|
||||||
else if (Cat inherits from std::input_iterator_tag)
|
} else if (tag <= input_iterator_tag)
|
||||||
typedef boost::readable_iterator_tag type;
|
typedef readable_iterator_tag type;
|
||||||
else if (Cat inherits from std::output_iterator_tag)
|
else if (tag <= output_iterator_tag)
|
||||||
typedef boost::writable_iterator_tag type;
|
typedef writable_iterator_tag type;
|
||||||
}
|
else
|
||||||
|
error;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -190,46 +265,47 @@ for <TT>T*</TT> are provided. <PRE>namespace std {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
struct traversal_category
|
class traversal_category
|
||||||
{
|
{
|
||||||
|
typedef iterator_traits<Iterator>::iterator_category tag;
|
||||||
|
public:
|
||||||
<B><I>// Pseudo-code</I></B>
|
<B><I>// Pseudo-code</I></B>
|
||||||
if (Iterator inherits from new_iterator_base) {
|
if (exists(tag::traversal)) // must be a new iterator
|
||||||
typedef typename Iterator::traversal_category type;
|
typedef tag::traversal type;
|
||||||
} else {
|
else if (tag <= random_access_iterator_tag)
|
||||||
typedef std::iterator_traits<Iterator> OldTraits;
|
typedef random_access_traversal_tag type;
|
||||||
typedef typename OldTraits::iterator_category Cat;
|
else if (tag <= bidirectional_iterator_tag)
|
||||||
|
typedef bidirectional_traversal_tag type;
|
||||||
if (Cat inherits from std::random_access_iterator_tag)
|
else if (tag <= is_forward_iterator_tag)
|
||||||
typedef boost::random_access_traversal_tag type;
|
typedef forward_traversal_tag type;
|
||||||
else if (Cat inherits from std::bidirectional_iterator_tag)
|
else if (tag <= input_iterator_tag)
|
||||||
typedef boost::bidirectional_traversal_tag type;
|
typedef input_traversal_tag type;
|
||||||
else if (Cat inherits from std::forward_iterator_tag)
|
else if (tag <= out_iterator_tag)
|
||||||
typedef boost::forward_traversal_tag type;
|
typedef output_traversal_tag type;
|
||||||
else if (Cat inherits from std::input_iterator_tag)
|
else
|
||||||
typedef boost::input_traversal_tag type;
|
error;
|
||||||
else if (Cat inherits from std::output_iterator_tag)
|
|
||||||
typedef boost::output_traversal_tag type;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct traversal_category<T*>
|
struct traversal_category<T*>
|
||||||
{
|
{
|
||||||
typedef boost::random_access_traversal_tag type;
|
typedef random_access_traversal_tag type;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
|
||||||
</PRE>
|
</PRE>
|
||||||
<H2>Impact on the Standard Algorithms</H2>Many of the standard algorithms place
|
|
||||||
more requirements than necessary on their iterator parameters due to the
|
<H2>Impact on the Standard Algorithms</H2>
|
||||||
coarseness of the current iterator categories. By using the new iterator
|
|
||||||
categories a better fit can be achieved, thereby increasing the reusability of
|
<P>Many of the standard algorithms place more requirements than
|
||||||
the algorithms. These changes will not affect user-code, though they will
|
necessary on their iterator parameters due to the coarseness of the
|
||||||
require changes by standard implementers: dispatching should be based on the new
|
current iterator categories. By using the new iterator categories a
|
||||||
categories, and in places return values may need to be handled more carefully.
|
better fit can be achieved, thereby increasing the reusability of the
|
||||||
In particular, uses of <TT>std::swap()</TT> will need to be replaced with
|
algorithms. These changes will not affect user-code, though they will
|
||||||
<TT>std::iter_swap()</TT>, and <TT>std::iter_swap()</TT> will need to call
|
require changes by standard implementers: dispatching should be based
|
||||||
<TT>std::swap()</TT>.
|
on the new categories, and in places return values may need to be
|
||||||
|
handled more carefully. In particular, uses of <TT>std::swap()</TT>
|
||||||
|
will need to be replaced with <TT>std::iter_swap()</TT>, and
|
||||||
|
<TT>std::iter_swap()</TT> will need to call <TT>std::swap()</TT>. </P>
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
<CENTER>
|
<CENTER>
|
||||||
<TABLE border=1>
|
<TABLE border=1>
|
||||||
|
Reference in New Issue
Block a user