220 lines
7.6 KiB
Plaintext
220 lines
7.6 KiB
Plaintext
[/
|
|
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
/]
|
|
|
|
[section Introduction]
|
|
|
|
Writing STL iterators, views, and containers is surprisingly hard. There are a
|
|
lot of things that can subtly go wrong. It is also very tedious, which of
|
|
course makes it error-prone.
|
|
|
|
Iterators have numerous typedefs and operations, even though all the
|
|
operations of a given iterator can be implemented in terms of at most four
|
|
operations (and usually only three). Writing all the other operations yields
|
|
very similar-looking code that is hard to review, and all but requires that
|
|
you write full-coverage tests for each iterator.
|
|
|
|
Writing view types like those found in `std::ranges` is also laborious,
|
|
considering that most of each view type's API can be derived from `begin()`
|
|
and `end()`. C++20 has a template that does exactly this,
|
|
`std::ranges::view_interface`; _IFaces_ provides a pre-C++20-friendly
|
|
implementation.
|
|
|
|
Most daunting of all is the task of writing a type or template that meets the
|
|
container requirements in the standard. _IFaces_ provides another template
|
|
called _cont_iface_ that reduces the implementation and testing burden
|
|
dramatically.
|
|
|
|
[note C++20 versions of _iter_iface_ and _cont_iface_ are provided (C++20
|
|
provides `std::view_interface`). These are constrained templates using C++20
|
|
concepts. These are in the `boost::stl_interfaces::v2` namespace, and are
|
|
considered experimental, because at the time of this writing, no
|
|
C++20-conforming compiler exists.]
|
|
|
|
[heading A Quick Example]
|
|
|
|
Here is an example of the iterator portion of the library. Let's say that we
|
|
wanted to make a random access iterator that represents a string of arbitrary
|
|
length constructed by repeating a shorter string. Let's call this iterator
|
|
`repeated_chars_iterator`. Here it is in action:
|
|
|
|
[repeated_chars_iterator_usage]
|
|
|
|
There's nothing in the standard library that gets us that kind of behavior, so
|
|
we have to write it. This library seeks to turn what we write from this:
|
|
|
|
struct repeated_chars_iterator
|
|
{
|
|
using value_type = char;
|
|
using difference_type = std::ptrdiff_t;
|
|
using pointer = char const *;
|
|
using reference = char const;
|
|
using iterator_category = std::random_access_iterator_tag;
|
|
|
|
constexpr repeated_chars_iterator() noexcept :
|
|
first_(nullptr),
|
|
size_(0),
|
|
n_(0)
|
|
{}
|
|
constexpr repeated_chars_iterator(
|
|
char const * first,
|
|
difference_type size,
|
|
difference_type n) noexcept :
|
|
first_(first),
|
|
size_(size),
|
|
n_(n)
|
|
{}
|
|
|
|
constexpr reference operator*() const noexcept
|
|
{
|
|
return first_[n_ % size_];
|
|
}
|
|
|
|
constexpr value_type operator[](difference_type n) const noexcept
|
|
{
|
|
return first_[(n_ + n) % size_];
|
|
}
|
|
|
|
constexpr repeated_chars_iterator & operator++() noexcept
|
|
{
|
|
++n_;
|
|
return *this;
|
|
}
|
|
constexpr repeated_chars_iterator operator++(int)noexcept
|
|
{
|
|
repeated_chars_iterator retval = *this;
|
|
++*this;
|
|
return retval;
|
|
}
|
|
constexpr repeated_chars_iterator & operator+=(difference_type n) noexcept
|
|
{
|
|
n_ += n;
|
|
return *this;
|
|
}
|
|
|
|
constexpr repeated_chars_iterator & operator--() noexcept
|
|
{
|
|
--n_;
|
|
return *this;
|
|
}
|
|
constexpr repeated_chars_iterator operator--(int)noexcept
|
|
{
|
|
repeated_chars_iterator retval = *this;
|
|
--*this;
|
|
return retval;
|
|
}
|
|
constexpr repeated_chars_iterator & operator-=(difference_type n) noexcept
|
|
{
|
|
n_ -= n;
|
|
return *this;
|
|
}
|
|
|
|
friend constexpr bool operator==(
|
|
repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept
|
|
{
|
|
return lhs.first_ == rhs.first_ && lhs.n_ == rhs.n_;
|
|
}
|
|
friend constexpr bool operator!=(
|
|
repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
friend constexpr bool operator<(
|
|
repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept
|
|
{
|
|
return lhs.first_ == rhs.first_ && lhs.n_ < rhs.n_;
|
|
}
|
|
friend constexpr bool operator<=(
|
|
repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept
|
|
{
|
|
return lhs == rhs || lhs < rhs;
|
|
}
|
|
friend constexpr bool operator>(
|
|
repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept
|
|
{
|
|
return rhs < lhs;
|
|
}
|
|
friend constexpr bool operator>=(
|
|
repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept
|
|
{
|
|
return rhs <= lhs;
|
|
}
|
|
|
|
friend constexpr repeated_chars_iterator
|
|
operator+(repeated_chars_iterator lhs, difference_type rhs) noexcept
|
|
{
|
|
return lhs += rhs;
|
|
}
|
|
friend constexpr repeated_chars_iterator
|
|
operator+(difference_type lhs, repeated_chars_iterator rhs) noexcept
|
|
{
|
|
return rhs += lhs;
|
|
}
|
|
friend constexpr repeated_chars_iterator
|
|
operator-(repeated_chars_iterator lhs, difference_type rhs) noexcept
|
|
{
|
|
return lhs -= rhs;
|
|
}
|
|
friend constexpr difference_type operator-(
|
|
repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept
|
|
{
|
|
return lhs.n_ - rhs.n_;
|
|
}
|
|
|
|
private:
|
|
char const * first_;
|
|
difference_type size_;
|
|
difference_type n_;
|
|
};
|
|
|
|
(that's a lot of code!) into this:
|
|
|
|
[repeated_chars_iterator]
|
|
|
|
Ah, that's better. Both of these definitions for `repeated_chars_iterator`
|
|
have the same semantics and performance profile. It's just a lot less code to
|
|
write the second one, and writing the second one is more novice-friendly.
|
|
|
|
[note _IFaces_'s `iterator_interface` implements iterators that model the
|
|
C++20 iterator concepts.]
|
|
|
|
[endsect]
|
|
|
|
[section This Library's Relationship to Boost.Iterator]
|
|
|
|
_Iterator_ is a library that is already in Boost, and it has been around for a
|
|
long time.
|
|
|
|
However, it was attempting to solve a lot of problems related to iterators,
|
|
not just how to write them from scratch. It is also not easy to modernize it
|
|
for use in C++11 and later. Specifically:
|
|
|
|
- _Iterator_ contains a large number of iterator adaptors; those have since
|
|
been rendered moot by C++20 ranges.
|
|
|
|
- _Iterator_'s `iterator_facade` template is not limited just to the
|
|
existing standard C++ iterator categories; that was an experiment that never
|
|
landed in standard C++, so it adds needless complexity.
|
|
|
|
- _Iterator_'s `iterator_facade` was written against C++98, so it is not
|
|
`constexpr`- and `noexcept`-friendly.
|
|
|
|
- _Iterator_'s `iterator_facade` does not support proxy iterators, which
|
|
are fully supported by the C++20 iterator concepts.
|
|
|
|
- There is opportunity to reduce the amount of code the user must write in
|
|
order to use `iterator_facade`.
|
|
|
|
- _Iterator_ contains two templates, `iterator_facade` and `iterator_adaptor`,
|
|
that represent two ways of writing a new iterator while writing as little
|
|
code as possible. It would be nice to have the functionality for both
|
|
available in one template, but it is difficult to unify those two templates
|
|
as written.
|
|
|
|
For these reasons, it seems more appropriate to introduce a new Boost library
|
|
than to try and address the shortcomings of _Iterator_'s `iterator_facade` and
|
|
`iterator_adaptor` templates directly.
|
|
|
|
[endsect]
|