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
  • Random - Access Traversal Iterator
  • 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 categories and traits classes

    Each of the new iterator requirements -will need a category tag.
    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().

    +