boost/libs/stl_interfaces/doc/intro.qbk
2021-10-05 21:37:46 +02:00

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]