diff --git a/doc/iterator-categories.html b/doc/iterator-categories.html index 43c80fd..eb76523 100644 --- a/doc/iterator-categories.html +++ b/doc/iterator-categories.html @@ -114,19 +114,28 @@ traversal: Traversal Iterator
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. -
namespace std { + Access Traversal Iterator + - // Return Type Categories +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.
+ +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.
+ +New category tags and traits classes
+ +The new iterator categories will require new tag classes.
+ +namespace std { + + // Returns Category Tags struct readable_iterator_tag { }; struct writable_iterator_tag { }; struct swappable_iterator_tag { }; @@ -134,7 +143,7 @@ will need a category tag.namespace std { virtual public readable_iterator_tag { }; struct constant_lvalue_iterator_tag : public readable_iterator_tag { }; - // Traversal Categories + // Traversal Category Tags struct input_traversal_tag { }; struct output_traversal_tag { }; struct forward_traversal_tag { }; @@ -142,41 +151,107 @@ will need a category tag.namespace std { struct random_access_traversal_tag : public bidirectional_traversal_tag { }; } -And there will need to be a way to access these category tags using a -traits mechanism. Adding new typedefs to std::iterator_traits 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 -backward compatible, that is, they should work with any iterator for -which there is a valid definition of std::iterator_traits. This can be -accomplished by making the default behavior of the traits classes map the -iterator_category 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 new_iterator_base (which is just a signal to the traits class that -it is a new iterator). As with std::iterator_traits, specializations -for T* are provided.namespace std { +- struct new_iterator_base { }; +Access to the return and traversal tags will be through the +following two traits classes, which have a member typedef named +type that provides the tag type. We explain the +definitions of these classes later.
+ ++ template <typename Iterator> + struct return_category; // contains: typedef ... type; template <typename Iterator> - struct return_category + struct traversal_category; // contains: typedef ... type; ++ +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 iterator_category typedef within +iterator_traits. + +
namespace std { + template <class ReturnTag, class TraversalTag> + struct iterator_tag : cvt_iterator_category<ReturnTag, TraversalTag>::type + { + typedef ReturnTag returns; + typedef TraversalTag traversal; + }; ++ +The cvt_iterator_category template computes the +appropriate old iterator category based on the return and traversal +category.
+ +namespace std { + template <class RC, class TC> + struct cvt_iterator_category + { + // Pseudo-code, <= means inherits or same type + 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; + }; +} ++ +The following is an example of a new iterator class using the +iterator_tag class to create its iterator_category +member typedef.
+ ++struct my_iterator { + typedef std::iterator_tag<std::readable_iterator_tag, + std::random_access_traversal_tag> iterator_category; + ... +}; ++ +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 return_category and traversal_category +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 +iterator_category tag. + + ++ template <typename Iterator> + class return_category { // Pseudo-code - if (Iterator inherits from new_iterator_base) { - typedef typename Iterator::return_category type; - } else { - typedef std::iterator_traits<Iterator> OldTraits; - typedef typename OldTraits::iterator_category Cat; - if (Cat inherits from std::forward_iterator_tag) - if (is-const(T)) - typedef boost::constant_lvalue_iterator_tag type; - else - typedef boost::mutable_lvalue_iterator_tag type; - else if (Cat inherits from std::input_iterator_tag) - typedef boost::readable_iterator_tag type; - else if (Cat inherits from std::output_iterator_tag) - typedef boost::writable_iterator_tag type; - } + typedef iterator_traits<Iterator>::iterator_category tag; + typedef iterator_traits<Iterator>::value_type T; + public: + if (exists(tag::returns)) // must be a new iterator + typedef tag::returns type; + else if (tag <= forward_iterator_tag) { + if (is-const(T)) + typedef constant_lvalue_iterator_tag type; + else + typedef mutable_lvalue_iterator_tag type; + } else if (tag <= input_iterator_tag) + typedef readable_iterator_tag type; + else if (tag <= output_iterator_tag) + typedef writable_iterator_tag type; + else + error; }; template <typename T> @@ -190,46 +265,47 @@ for T* are provided.namespace std { }; template <typename Iterator> - struct traversal_category + class traversal_category { + typedef iterator_traits<Iterator>::iterator_category tag; + public: // Pseudo-code - if (Iterator inherits from new_iterator_base) { - typedef typename Iterator::traversal_category type; - } else { - typedef std::iterator_traits<Iterator> OldTraits; - typedef typename OldTraits::iterator_category Cat; - - if (Cat inherits from std::random_access_iterator_tag) - typedef boost::random_access_traversal_tag type; - else if (Cat inherits from std::bidirectional_iterator_tag) - typedef boost::bidirectional_traversal_tag type; - else if (Cat inherits from std::forward_iterator_tag) - typedef boost::forward_traversal_tag type; - else if (Cat inherits from std::input_iterator_tag) - typedef boost::input_traversal_tag type; - else if (Cat inherits from std::output_iterator_tag) - typedef boost::output_traversal_tag type; - } + if (exists(tag::traversal)) // must be a new iterator + typedef tag::traversal type; + else if (tag <= random_access_iterator_tag) + typedef random_access_traversal_tag type; + else if (tag <= bidirectional_iterator_tag) + typedef bidirectional_traversal_tag type; + else if (tag <= is_forward_iterator_tag) + typedef forward_traversal_tag type; + else if (tag <= input_iterator_tag) + typedef input_traversal_tag type; + else if (tag <= out_iterator_tag) + typedef output_traversal_tag type; + else + error; }; template <typename T> struct traversal_category<T*> { - typedef boost::random_access_traversal_tag type; + typedef random_access_traversal_tag type; }; - -}-Impact on the Standard Algorithms
Many of the standard algorithms place -more requirements than necessary on their iterator parameters due to the -coarseness of the current iterator categories. By using the new iterator -categories a better fit can be achieved, thereby increasing the reusability of -the algorithms. These changes will not affect user-code, though they will -require changes by standard implementers: dispatching should be based on the new -categories, and in places return values may need to be handled more carefully. -In particular, uses of std::swap() will need to be replaced with -std::iter_swap(), and std::iter_swap() will need to call -std::swap(). + +Impact on the Standard Algorithms
+ +Many of the standard algorithms place more requirements than +necessary on their iterator parameters due to the coarseness of the +current iterator categories. By using the new iterator categories a +better fit can be achieved, thereby increasing the reusability of the +algorithms. These changes will not affect user-code, though they will +require changes by standard implementers: dispatching should be based +on the new categories, and in places return values may need to be +handled more carefully. In particular, uses of std::swap() +will need to be replaced with std::iter_swap(), and +std::iter_swap() will need to call std::swap().
+