File: reverseiterator.yo

package info (click to toggle)
c%2B%2B-annotations 13.02.02-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,576 kB
  • sloc: cpp: 25,297; makefile: 1,523; ansic: 165; sh: 126; perl: 90; fortran: 27
file content (103 lines) | stat: -rw-r--r-- 5,892 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    Once we've implemented an iterator, the matching emi(reverse iterator) can
be implemented in a jiffy. To implement a reverse_iterator
tt(std::reverse_iterator) hi(reverse_iterator) is used, which nicely
implements the reverse iterator once we have defined an iterator. Its
constructor merely requires an object of the iterator type for which we want
to construct a reverse iterator.

    To implement a reverse iterator for tt(StringPtr) we only need to define
the tt(reverse_iterator) type in its interface. This requires us to specify
only one line of code, which must be inserted after the interface of the class
tt(iterator):
        verb(    using reverse_iterator = std::reverse_iterator<iterator>;)

Also, the well-known members ti(rbegin) and ti(rend) are added to
tt(StringPtr)'s interface. Again, they can easily be implemented inline:
        verbinclude(//RBEGEND examples/stringptrs/stringptr.h)
    Note the arguments the tt(reverse_iterator) constructors receive: the
        hi(reverse_iterator: initialized by iterator)
    em(begin point) of the reversed iterator is obtained by providing
tt(reverse_iterator)'s constructor with the value returned by the member
tt(end): the em(endpoint) of the normal iterator range; the em(endpoint) of
the reversed iterator is obtained by providing tt(reverse_iterator)'s
constructor with the value returned by the member tt(begin): the em(begin
point) of the normal iterator range.

    The following program illustrates the use of tt(StringPtr)'s
tt(RandomAccessIterator):
        verbinclude(-a examples/stringptrs/iterators.cc)
    Although it is thus possible to construct a reverse iterator from a normal
iterator, the opposite does not hold true: it is not possible to
initialize a normal iterator from a reverse iterator.

    Assume we would like to process all lines stored in tt(vector<string>
lines) up to any trailing empty lines (or lines only containing blanks) it
might contain. How should we proceed? One approach is to start the processing
from the first line in the vector, continuing until the first of the trailing
empty lines. However, once we encounter an empty line it does of course not
have to be the first line of the set of trailing empty lines. In that case,
we'd better use the following algorithm:
    itemization(
    it() First, use
        verb(    rit = find_if(lines.rbegin(), lines.rend(), NonEmpty());)

to obtain a tt(reverse_iterator rit) pointing to the last non-empty
        line.
    it() Next, use
        verb(    for_each(lines.begin(), --rit, Process());)

to process all lines up to the first empty line.
    )
    However, we can't mix iterators and reverse iterators when using generic
algorithms. So how can we initialize the second iterator using the available
tt(reverse_iterator)? The solution is not very difficult, as an iterator may
be initialized from a pointer. Although the reverse iterator tt(rit) is not a
pointer, tt(&*(rit - 1)) or tt(&*--rit) em(is). So we use
        verb(    for_each(lines.begin(), &*--rit, Process());)
    to process all the lines up to the first of the set of trailing empty
lines. In general, if tt(rit) is a tt(reverse_iterator) pointing to some
element and we need an tt(iterator) to point to that element, we may use
tt(&*rit) to initialize the iterator. Here, the dereference operator is
applied to reach the element the reverse iterator refers to. Then the address
operator is applied to obtain its address with which we can initialize the
iterator.

    When defining a tt(const_reverse_iterator) (e.g., matching a
tt(const_iterator) class), then the tt(const_iterator's operator*) member
should be a member returning a non-modifiable value or object. Since a
tt(const_reverse_iterator) uses the iterator's ttNoCt(operator--) member,
we're running against a small conceptual conflict. On the one hand, a
tt(std::input_iterator_tag) is inappropriate, since we must allow decrementing
the iterator. On the other hand, a tt(std::bidirectional_iterator) is
inappropriate, since we don't allow modification of the data.

    Iterator tags are primarily conceptual. If tt(const_iterators) and
tt(const_reverse_iterators) only allow increment operations, then an
tt(input_iterator_tag) is the best match for the iterator's intended
use. Hence this tag is used below.

    Furthermore, in line with the nature of a tt(input_iterator_tag) our
tt(const_iterator) should not offer an ttNoCt(operator--). This, of course,
causes problems: a reverse iterator must be able to use the iterator's
ttNoCt(operator--) member. This can easily be solved by stashing the iterator's
ttNoCt(operator--) in the iterator's private section, and declaring
tt(std::reverse_iterator<(const_)iterator>) its friend (note that declaring a
tt((const_)reverse_iterator) that is derived from tt(std::reverse_iterator)
doesn't solve the issue: it is tt(std::reverse_iterator) that calls the
iterator's ttNoCt(operator--), not a class that is derived from it).

    To keep the const-ness of dereferencing tt(const_iterator) iterators
tt(using) specification can added to the tt(const_iterator) class. The
tt(using) specifications provided by tt(Data::iterator) are inherited by
tt(Data::const_iterator), but tt(Data::const_iterator) may also specify:
        verb(    using const_pointer   = value_type const *;
    using const_reference = value_type const &;)
    whereafter its tt(operator *()) can return a tt(const_reference).

    The elements involved in defining an tt(iterator, const_iterator,
reverse_iterator) and tt(const_reverse_iterator) for a class tt(Data) is
illustrated in the following example, which only requires the definitions of
the tt(iterator) and tt(const_iterator) classes, as these types can be passed
to the tt(reverse_iterator) template to obtain the corresponding
reverse-iterators:
    verbinclude(-a examples/stringptrs/reverseiterators.cc)