From ddbc51420844d6ab0f13975163c7740c43b92750 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sat, 1 Sep 2001 20:59:13 +0000 Subject: [PATCH] total reorg. Whew! [SVN r10989] --- tmpw2001-paper/iter-adaptor.tex | 506 ++++++++++++++++++-------------- 1 file changed, 278 insertions(+), 228 deletions(-) diff --git a/tmpw2001-paper/iter-adaptor.tex b/tmpw2001-paper/iter-adaptor.tex index 1d87edd..41901fd 100644 --- a/tmpw2001-paper/iter-adaptor.tex +++ b/tmpw2001-paper/iter-adaptor.tex @@ -205,8 +205,17 @@ in which a variety of adaptor types are enumerated. \section{The Boost Iterator Adaptor Library} -% Do we need a section body? -In this section, we present the Boost Iterator Adaptor Library. +% We need an intro here (do we?), but I don't think the text below +% fits in. Suggestions? + +% For an iterator to be usable with the Standard algorithms (and other +% generic algorithms), it must fulfill the Standard requirements for an +% iterator type, which range from the few requirements of an +% \stlconcept{InputIterator} to the many requirements of a +% \stlconcept{RandomAccessIterator}. Implementing an iterator class that +% meets these requirements is a tedious and error-prone task despite the +% fact that most iterators are conceptually simple. The Boost Iterator +% Adaptor Library addresses these problems. \subsection{Overall Design} @@ -222,7 +231,7 @@ the use of inheritance. We have followed the lead of the standard library, which provides a \code{base()} function to access the underlying iterator object of a \reverseiterator\ adaptor.} -\subsubsection{Core Elements of the Concept} +\subsection{Core Elements of the Concept} The first step in designing such a generalized Model is to identify the core elements of its interface. We have identified the following @@ -247,16 +256,16 @@ these: as traditional and also as \emph{named} template parameters (described below), and uses a system of smart defaults which in most cases reduces the number of these types that must be specified. -\subsubsection{From Building Models to Building Adaptors} +\subsection{From Building Models to Building Adaptors} A generalized iterator is useful, but a generalized iterator \emph{adaptor} would be even more useful. One could then build specialized adaptors to generate new families of iterator instances based on existing iterators. In the Boost Iterator Adaptor Library, -the role of adaptor is also played by the \iteratoradaptor\ class -template. The behaviors of \iteratoradaptor{} instances are supplied -through a Policies class~\cite{alexandrescu01:_modern_cpp_design} -which allows allows users to specialize adaptation. They go beyond +the \iteratoradaptor\ class template plays the roles of both Adaptor +and Model. The behaviors of \iteratoradaptor{} instances are supplied +through a policies class~\cite{alexandrescu01:_modern_cpp_design} +which allows allows users to specialize adaptation. Users go beyond generating new iterator types to easily generating new iterator adaptor families. @@ -277,8 +286,16 @@ show how this adaptor is implemented below. Iterator Adaptor except that when dereferenced it returns by-reference instead of by-value. - \item Filter Iterator Adaptor, which view of an iterator range in - which some elements of the range are skipped over. + \item Filter Iterator Adaptor, which provides a view of an iterator + range in which some elements of the underlying range are skipped. + + \item Counting Iterator Adaptor, which adapts any incrementable type +(e.g. integers, iterators) so that incrementing/decrementing the +adapted iterator and dereferencing it produces successive values of +the \code{Base} type. + + \item Function Output Iterator Adaptor, which makes it easier to +create custom output iterators. \end{itemize} @@ -288,222 +305,6 @@ permutation to a \stlconcept{RandomAccessIterator}, and a strided adaptor, which adapts a \stlconcept{RandomAccessIterator} by multiplying its unit of motion by a constant factor. -% In addition, large number of iterator adaptors are now in use: -% iterators that that conforms to the Conceptual -% requirements of its iterator category - -% For an iterator to be usable with the Standard algorithms (and other -% generic algorithms in third-party libraries), it must fulfill the -% Standard requirements for an iterator type, which range from the few -% requirements of an \stlconcept{InputIterator} to the many requirements -% of a \stlconcept{RandomAccessIterator}. Implementing an iterator class -% that meets these requirements is a tedious and error-prone task -% despite the fact that most iterators are conceptually simple. - -\subsection{Redundant Operators} - -Perhaps the most obvious reason that implementing an iterator can -be tedious is that there are lots of redundant operators. That is, -there are many operators that can be trivially defined in terms of -other operators. For example, the postfix \code{operator++(int)} is often best -implemented in terms of prefix \code{operator++()} as shown below. - -{\footnotesize -\begin{verbatim} - class iter { - // ... - iter& operator++() { /* ... */ return *this; } - iter operator++(int) { iter tmp(*this); ++*this; return tmp; } - }; -\end{verbatim} -} - -For a full \stlconcept{RandomAccessIterator}, there are a total of 17 -operators. 7 of the operators are fundamental while the other 10 are -redundant. - -% 7 core operations -% 10 derived operations - -% \code{operator->} -% \code{operator[]} -% \code{operator++(int)}, -% \code{operator--(int)}, -% \code{operator-=}, -% \code{operator+}, -% \code{operator!=}, -% \code{operator>}, -% \code{operator<=}, -% \code{operator>=} - - -\subsection{Delegation of Operators and Type Definitions} - -An iterator adaptor used to adapt an underlying iterator type often -changes the meaning of one or two operators while leaving the rest of -the operators defined in the same way as in the base iterator. This -is typically implemented with delegating functions.\footnote{Although -one might normally consider parametrized inheritance for cases where -many functions must be forwarded, that is not possible for a -generalized iterator adaptor because the underlying type may be a -pointer} The following example shows an excerpt from an -\code{indirect\_iterator} adaptor, which takes an iterator over -pointers or smart-pointers and creates an iterator over the things -pointed to. The \code{operator*} and \code{operator->} are changed to -dereference twice but all the other operators stay the same. Writing -all of the delegating functions for the \code{indirect\_iterator} is a -tedious job. - -{\footnotesize -\begin{verbatim} - template class indirect_iterator { - public: - // Adapt the meaning of dereference - reference operator*() const { - return **iter; // dereference twice - } - // a ``redundant'' operator - pointer operator->() const { return &this->operator*(); } % dwa -- changed for clarity. I don't think the review comment was correct. - // Delegating the implementation to the underlying iterator. - indirect_iterator& operator++() { ++iter; return *this; } - indirect_iterator& operator--() { --iter; return *this; } - // delegate for all the other operators... - private: - Base iter; - }; -\end{verbatim} -} - -% I think it would be better to use reverse_iterator as an example -% here, because it delegates more types than indirect_iterator does. -% But reverse_iterator doesn't delegate many operators... it changes -% the meaning of all of them. I wonder if there's a good example -% for both operators and typedefs. -A standard-conforming iterator must either come with a specialization -of \code{std::iterator\_\-traits<>} or it must define five nested -types: \valuetype{}, \code{reference}, \code{pointer}, -\differencetype{}, and \iteratorcategory{}. In the -example above, the last two would be delegated to the \code{Base} -iterator type. For many iterator adaptors, all five must be delegated. - -\subsection{Iterator Implementation Complexities} - -In addition to the tedious aspects of iterator implementation, there -are some complexities that trip up even the most experienced of -programmers. Ideally, an iterator implementer should not have to worry -about these details. - -\subsubsection{Constant/Mutable Iterator Interactions} -\label{sec:constant-mutable-iterations} - -Iterators over containers and other sequences of stored objects -usually come in pairs: a constant iterator type and a mutable iterator -type. It is desirable to allow the constant and mutable iterators to -interoperate through comparison and -subtraction. For example, suppose -that you are implementing a container type \code{C}. Then you ought to -define the following four versions of \code{operator==}, along with -corresponding versions of \code{operator!=}, and (for -\stlconcept{RandomAccessIterator}), operators \code{<}, \code{>}, -\code{<=}, \code{>=}, and \code{-}. - -{\footnotesize -\begin{verbatim} - bool operator==(const C::iterator& x, const C::iterator& y); - bool operator==(const C::const_iterator& x, const C::iterator& y); - bool operator==(const C::iterator& x, const C::const_iterator& y); - bool operator==(const C::const_iterator& x, const C::const_iterator& y); -\end{verbatim} -} - -Implementers often forget to define the operators for constant/mutable -iterator interaction. In addition, iterator adaptors applied to these -kinds of iterators should propagate the ability to interact. For -example, a reverse iterator adaptor applied to \code{C::iterator} and -\code{C::const\_iterator} should result in mutable and constant reverse iterator types that -have the same ability to interact as the \code{Base} iterators do. - -\subsubsection{Constant/Mutable Iterator Code Duplication} - -% Is this section really worthwhile? It was confusing to read until I -% finally figured out what you were driving at. Who makes this conceptual mistake? -% It may not be worthwhile... though I've seen other grad students make -% this mistake, and the TMPW2000 VTL paper contains this mistake. - -The implementations of the constant and mutable versions of an -iterator typically differ only in their \code{reference} and -\code{pointer} types. Therefore it is desirable to merge the two -iterator classes into a single class template with the -\code{reference} and \code{pointer} types as template parameters. - -Some care must be taken when merging the constant and mutable -iterators. One common mistake is that the programmer will confuse the -ideas of a \code{const} iterator object and a \emph{constant -iterator}. Such a misunderstanding can, for example, lead to an -iterator class template that has two versions of \code{operator*}, one -that is a \code{const} member function and one that is not. - -{\footnotesize -\begin{verbatim} - // this is a mistake - reference operator*(); - const_reference operator*() const; -\end{verbatim} -} - -There should be only one \code{operator*} that returns the -\code{reference} type and the member function should be \code{const} since -dereferencing an iterator does not change the state of the iterator -object itself (unlike \code{operator++}). - -{\footnotesize -\begin{verbatim} - // this is right - reference operator*() const; -\end{verbatim} -} - - -\subsubsection{Input Iterators and \code{operator->}} -\label{sec:operator-arrow} - -When creating an iterator adaptor that produces an -\stlconcept{InputIterator} some extra care must be taken in the -implementation of \code{operator->}. Remember that an input iterator -need not iterate over stored objects: it can manufacture new objects -when it is dereferenced as is the case for -\code{std::istream\_iterator}. If the iterator's \valuetype\ is -of class type, we need to support \code{operator->}. Since the result -of using \code{operator->} must produce a true pointer even when -dereferencing the iterator does not yield a true reference type, we -need a \code{const} lvalue to which a pointer can be formed. In -\S\ref{sec:operator-arrow} we show how this can be accomplished. - - -\subsubsection{The Return Type of \code{operator[]} for Adaptors} -\label{sec:operator-bracket} - -The \Cpp\ Standard specifies that the return type of \code{operator[]} -of a random access iterator must be ``convertible to \code{T}''. This -is a rather lenient requirement since \code{operator*} is required to -return the exact type \code{T\&}, and one might think that -\code{operator[]} and \code{operator*} should be same in this respect. -The \Cpp\ Standards Committee is currently debating as to whether the -random access iterator requirements should be changed. - -To complicate the matter, returning \code{T\&} from \code{operator[]} -causes a run-time error in a certain class of situations. We will -discuss this in detail in \S\ref{sec:op-bracket-impl}. - - -% Automatic implementation of redundant operators -% Default delegation to adapted iterator - -% complexities: -% const-non const interaction -% const/mutable iterator distinction -% input iterator \code{operator->} - \section{The Boost \iteratoradaptor\ Class Template} The \iteratoradaptor\ class template simplifies the creation @@ -511,11 +312,11 @@ of iterators by automating the implementation of redundant operators and delegating functions and by taking care of the complex details of iterator implementation. -The central design feature of \iteratoradaptor\ is the +The central design feature of \iteratoradaptor\ is parameterization by an iterator policies class. The policies class is the primary communication mechanism between the iterator implementer and the \iteratoradaptor{}; it specifies how the new iterator -type is different from the \code{Base} type. Unlike the policy classes +type is behaves. Unlike the policy classes in~\cite{alexandrescu01:_modern_cpp_design}, we group several policies into a single class as this proved more convenient for iterator implementation. @@ -782,6 +583,255 @@ negate the numbers over which it iterates. \end{verbatim} } +\section{The Policy Adaptor Design Pattern} + +The Iterator Adaptor Library illustrates how a generalized Model +(\iteratoradaptor{}) of a Concept family (iterators) combined with +default policy delegation allows users to easily build new Models and +behavioral adaptors for existing Models. We can capture this strategy +in the Policy Adaptor design pattern:\footnote{This is not quite the +same as the Policy Class pattern which has been discussed previously +in the literature~\cite{alexandrescu01:_modern_cpp_design}. The +construction of an adaptor which can easily transforms existing Models +into new ones is the key difference}\begin{itemize} + +% Jeremy, can we get a numbered list here? + \item First, identify the core elements of the Adaptor Concept's + public interface. In our case, the Adaptor Concept is Iterator. + + \item then, encapsulate core elements of the Concept family in a +Policies Concept. + + \item Write a default policies class which delegates behavior to the +public interface of the Adaptor Concept. This is the mechanism that +supplies default adaptation behavior. + + \item build an Adaptor class template parameterized on Policies. The +Adaptor should be a generalized model of the Adaptor Concept, +providing the public interface, but delegating functionality to the +policies class. + + \item Store a member of the Policies parameter in the Adaptor +template so that users can store additional data while taking +advantage of default behavior delegation. + +\end{itemize} + +While the This pattern has not yet been widely tested for +applicability, we believe it will be useful for modelling any Concept +which varies along several axes and contains significant +redundancy. + +% In addition, large number of iterator adaptors are now in use: +% iterators that that conforms to the Conceptual +% requirements of its iterator category + + +\section{The Iterator Implementation Generator} + +\subsection{Redundant Operators} + +Perhaps the most obvious reason that implementing an iterator can +be tedious is that there are lots of redundant operators. That is, +there are many operators that can be trivially defined in terms of +other operators. For example, the postfix \code{operator++(int)} is often best +implemented in terms of prefix \code{operator++()} as shown below. + +{\footnotesize +\begin{verbatim} + class iter { + // ... + iter& operator++() { /* ... */ return *this; } + iter operator++(int) { iter tmp(*this); ++*this; return tmp; } + }; +\end{verbatim} +} + +For a full \stlconcept{RandomAccessIterator}, there are a total of 17 +operators. 7 of the operators are fundamental while the other 10 are +redundant. + +% 7 core operations +% 10 derived operations + +% \code{operator->} +% \code{operator[]} +% \code{operator++(int)}, +% \code{operator--(int)}, +% \code{operator-=}, +% \code{operator+}, +% \code{operator!=}, +% \code{operator>}, +% \code{operator<=}, +% \code{operator>=} + + +\subsection{Delegation of Operators and Type Definitions} + +An iterator adaptor used to adapt an underlying iterator type often +changes the meaning of one or two operators while leaving the rest of +the operators defined in the same way as in the base iterator. This +is typically implemented with delegating functions.\footnote{Although +one might normally consider parametrized inheritance for cases where +many functions must be forwarded, that is not possible for a +generalized iterator adaptor because the underlying type may be a +pointer} The following example shows an excerpt from an +\code{indirect\_iterator} adaptor, which takes an iterator over +pointers or smart-pointers and creates an iterator over the things +pointed to. The \code{operator*} and \code{operator->} are changed to +dereference twice but all the other operators stay the same. Writing +all of the delegating functions for the \code{indirect\_iterator} is a +tedious job. + +{\footnotesize +\begin{verbatim} + template class indirect_iterator { + public: + // Adapt the meaning of dereference + reference operator*() const { + return **iter; // dereference twice + } + // a ``redundant'' operator + pointer operator->() const { return &this->operator*(); } % dwa -- changed for clarity. I don't think the review comment was correct. + // Delegating the implementation to the underlying iterator. + indirect_iterator& operator++() { ++iter; return *this; } + indirect_iterator& operator--() { --iter; return *this; } + // delegate for all the other operators... + private: + Base iter; + }; +\end{verbatim} +} + +% I think it would be better to use reverse_iterator as an example +% here, because it delegates more types than indirect_iterator does. +% But reverse_iterator doesn't delegate many operators... it changes +% the meaning of all of them. I wonder if there's a good example +% for both operators and typedefs. +A standard-conforming iterator must either come with a specialization +of \code{std::iterator\_\-traits<>} or it must define five nested +types: \valuetype{}, \code{reference}, \code{pointer}, +\differencetype{}, and \iteratorcategory{}. In the +example above, the last two would be delegated to the \code{Base} +iterator type. For many iterator adaptors, all five must be delegated. + +\subsection{Iterator Implementation Complexities} + +In addition to the tedious aspects of iterator implementation, there +are some complexities that trip up even the most experienced of +programmers. Ideally, an iterator implementer should not have to worry +about these details. + +\subsubsection{Constant/Mutable Iterator Interactions} +\label{sec:constant-mutable-iterations} + +Iterators over containers and other sequences of stored objects +usually come in pairs: a constant iterator type and a mutable iterator +type. It is desirable to allow the constant and mutable iterators to +interoperate through comparison and +subtraction. For example, suppose +that you are implementing a container type \code{C}. Then you ought to +define the following four versions of \code{operator==}, along with +corresponding versions of \code{operator!=}, and (for +\stlconcept{RandomAccessIterator}), operators \code{<}, \code{>}, +\code{<=}, \code{>=}, and \code{-}. + +{\footnotesize +\begin{verbatim} + bool operator==(const C::iterator& x, const C::iterator& y); + bool operator==(const C::const_iterator& x, const C::iterator& y); + bool operator==(const C::iterator& x, const C::const_iterator& y); + bool operator==(const C::const_iterator& x, const C::const_iterator& y); +\end{verbatim} +} + +Implementers often forget to define the operators for constant/mutable +iterator interaction. In addition, iterator adaptors applied to these +kinds of iterators should propagate the ability to interact. For +example, a reverse iterator adaptor applied to \code{C::iterator} and +\code{C::const\_iterator} should result in mutable and constant reverse iterator types that +have the same ability to interact as the \code{Base} iterators do. + +\subsubsection{Constant/Mutable Iterator Code Duplication} + +% Is this section really worthwhile? It was confusing to read until I +% finally figured out what you were driving at. Who makes this conceptual mistake? +% It may not be worthwhile... though I've seen other grad students make +% this mistake, and the TMPW2000 VTL paper contains this mistake. + +The implementations of the constant and mutable versions of an +iterator typically differ only in their \code{reference} and +\code{pointer} types. Therefore it is desirable to merge the two +iterator classes into a single class template with the +\code{reference} and \code{pointer} types as template parameters. + +Some care must be taken when merging the constant and mutable +iterators. One common mistake is that the programmer will confuse the +ideas of a \code{const} iterator object and a \emph{constant +iterator}. Such a misunderstanding can, for example, lead to an +iterator class template that has two versions of \code{operator*}, one +that is a \code{const} member function and one that is not. + +{\footnotesize +\begin{verbatim} + // this is a mistake + reference operator*(); + const_reference operator*() const; +\end{verbatim} +} + +There should be only one \code{operator*} that returns the +\code{reference} type and the member function should be \code{const} since +dereferencing an iterator does not change the state of the iterator +object itself (unlike \code{operator++}). + +{\footnotesize +\begin{verbatim} + // this is right + reference operator*() const; +\end{verbatim} +} + + +\subsubsection{Input Iterators and \code{operator->}} +\label{sec:operator-arrow} + +When creating an iterator adaptor that produces an +\stlconcept{InputIterator} some extra care must be taken in the +implementation of \code{operator->}. Remember that an input iterator +need not iterate over stored objects: it can manufacture new objects +when it is dereferenced as is the case for +\code{std::istream\_iterator}. If the iterator's \valuetype\ is +of class type, we need to support \code{operator->}. Since the result +of using \code{operator->} must produce a true pointer even when +dereferencing the iterator does not yield a true reference type, we +need a \code{const} lvalue to which a pointer can be formed. In +\S\ref{sec:operator-arrow} we show how this can be accomplished. + + +\subsubsection{The Return Type of \code{operator[]} for Adaptors} +\label{sec:operator-bracket} + +The \Cpp\ Standard specifies that the return type of \code{operator[]} +of a random access iterator must be ``convertible to \code{T}''. This +is a rather lenient requirement since \code{operator*} is required to +return the exact type \code{T\&}, and one might think that +\code{operator[]} and \code{operator*} should be same in this respect. +The \Cpp\ Standards Committee is currently debating as to whether the +random access iterator requirements should be changed. + +To complicate the matter, returning \code{T\&} from \code{operator[]} +causes a run-time error in a certain class of situations. We will +discuss this in detail in \S\ref{sec:op-bracket-impl}. + + +% Automatic implementation of redundant operators +% Default delegation to adapted iterator + +% complexities: +% const-non const interaction +% const/mutable iterator distinction +% input iterator \code{operator->} \section{The Implementation of \iteratoradaptor{}}