Boost.Hana  1.6.0
Your standard library for metaprogramming
Iterable

Description

The Iterable concept represents data structures supporting external iteration.

Intuitively, an Iterable can be seen as a kind of container whose elements can be pulled out one at a time. An Iterable also provides a way to know when the container is empty, i.e. when there are no more elements to pull out.

Whereas Foldable represents data structures supporting internal iteration with the ability to accumulate a result, the Iterable concept allows inverting the control of the iteration. This is more flexible than Foldable, since it allows iterating over only some part of the structure. This, in turn, allows Iterable to work on infinite structures, while trying to fold such a structure would never finish.

Minimal complete definition

at, drop_front and is_empty

The linearization of an Iterable

Intuitively, for an Iterable structure xs, the linearization of xs is the sequence of all the elements in xs as if they had been put in a (possibly infinite) list:

linearization(xs) = [x1, x2, x3, ...]

The nth element of the linearization of an Iterable can be accessed with the at function. In other words, at(xs, n) == xn.

Note that this notion is precisely the extension of the linearization notion of Foldables to the infinite case. This notion is useful for expressing various properties of Iterables, and is used for that elsewhere in the documentation.

Compile-time Iterables

A compile-time Iterable is an Iterable for which is_empty returns a compile-time Logical. These structures allow iteration to be done at compile-time, in the sense that the "loop" doing the iteration can be unrolled because the total length of the structure is kown at compile-time.

In particular, note that being a compile-time Iterable has nothing to do with being finite or infinite. For example, it would be possible to create a sequence representing the Pythagorean triples as integral_constants. Such a sequence would be infinite, but iteration on the sequence would still be done at compile-time. However, if one tried to iterate over all the elements of the sequence, the compiler would loop indefinitely, in contrast to your program looping indefinitely if the sequence was a runtime one.

In the current version of the library, only compile-time Iterables are supported. While it would be possible in theory to support runtime Iterables, doing it efficiently is the subject of some research. In particular, follow this issue for the current status of runtime Iterables.

Laws

First, we require the equality of two Iterables to be related to the equality of the elements in their linearizations. More specifically, if xs and ys are two Iterables of data type It, then

xs == ys => at(xs, i) == at(ys, i) for all i

This conveys that two Iterables must have the same linearization in order to be considered equal.

Secondly, since every Iterable is also a Searchable, we require the models of Iterable and Searchable to be consistent. This is made precise by the following laws. For any Iterable xs with a linearization of [x1, x2, x3, ...],

any_of(xs, equal.to(z)) <=> xi == z

for some finite index i. Furthermore,

find_if(xs, pred) == just(the first xi such that pred(xi) is satisfied)

or nothing if no such xi exists.

Refined concepts

  1. Searchable (free model)
    Any Iterable gives rise to a model of Searchable, where the keys and the values are both the elements in the structure. Searching for a key is just doing a linear search through the elements of the structure.
    // Copyright Louis Dionne 2013-2017
    // Distributed under the Boost Software License, Version 1.0.
    // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
    #include <type_traits>
    namespace hana = boost::hana;
    // First get the type of the object, and then call the trait on it.
    constexpr auto is_integral = hana::compose(hana::trait<std::is_integral>, hana::typeid_);
    constexpr auto is_class = hana::compose(hana::trait<std::is_class>, hana::typeid_);
    static_assert(
    hana::find_if(hana::make_tuple(1.0, 2, '3'), is_integral)
    ==
    hana::just(2)
    , "");
    hana::find_if(hana::make_tuple(1.0, 2, '3'), is_class)
    ==
    hana::nothing
    );
    hana::find(hana::make_tuple(hana::int_c<1>, hana::char_c<'c'>, hana::type_c<void>), hana::type_c<void>)
    ==
    hana::just(hana::type_c<void>)
    );
    hana::find(hana::make_tuple(hana::int_c<1>, hana::char_c<'c'>, hana::type_c<void>), hana::type_c<int>)
    ==
    hana::nothing
    );
    int main() { }
  2. Foldable for finite Iterables
    Every finite Iterable gives rise to a model of Foldable. For these models to be consistent, we require the models of both Foldable and Iterable to have the same linearization.
Note
As explained above, Iterables are also Searchables and their models have to be consistent. By the laws presented here, it also means that the Foldable model for finite Iterables has to be consistent with the Searchable model.

For convenience, finite Iterables must only provide a definition of length to model the Foldable concept; defining the more powerful unpack or fold_left is not necessary (but still possible). The default implementation of unpack derived from Iterable + length uses the fact that at(xs, i) denotes the ith element of xs's linearization, and that the linearization of a finite Iterable must be the same as its linearization as a Foldable.

Concrete models

hana::tuple, hana::string, hana::range

Variables

constexpr auto boost::hana::at
 Returns the nth element of an iterable.Given an Iterable and an IntegralConstant index, at returns the element located at the index in the linearization of the iterable. Specifically, given an iterable xs with a linearization of [x1, ..., xN], at(xs, k) is equivalent to xk. More...
 
template<std::size_t n>
constexpr auto boost::hana::at_c
 Equivalent to at; provided for convenience. More...
 
constexpr auto boost::hana::back
 Returns the last element of a non-empty and finite iterable.Given a non-empty and finite iterable xs with a linearization of [x1, ..., xN], back(xs) is equal to xN. Equivalently, back(xs) must be equivalent to at_c<N-1>(xs), and that regardless of the value category of xs (back must respect the reference semantics of at). More...
 
constexpr auto boost::hana::drop_front
 Drop the first n elements of an iterable, and return the rest.Given an Iterable xs with a linearization of [x1, x2, ...] and a non-negative IntegralConstant n, drop_front(xs, n) is an iterable with the same tag as xs whose linearization is [xn+1, xn+2, ...]. In particular, note that this function does not mutate the original iterable in any way. If n is not given, it defaults to an IntegralConstant with a value equal to 1. More...
 
constexpr auto boost::hana::drop_front_exactly
 Drop the first n elements of an iterable, and return the rest.Given an Iterable xs with a linearization of [x1, x2, ...] and a non-negative IntegralConstant n, drop_front_exactly(xs, n) is an iterable with the same tag as xs whose linearization is [xn+1, xn+2, ...]. In particular, note that this function does not mutate the original iterable in any way. If n is not given, it defaults to an IntegralConstant with a value equal to 1. More...
 
constexpr auto boost::hana::drop_while
 Drop elements from an iterable up to, but excluding, the first element for which the predicate is not satisfied.Specifically, drop_while returns an iterable containing all the elements of the original iterable except for those in the range delimited by [head, e), where head is the first element and e is the first element for which the predicate is not satisfied. If the iterable is not finite, the predicate has to return a false- valued Logical at a finite index for this method to return. More...
 
constexpr auto boost::hana::front
 Returns the first element of a non-empty iterable.Given a non-empty Iterable xs with a linearization of [x1, ..., xN], front(xs) is equal to x1. If xs is empty, it is an error to use this function. Equivalently, front(xs) must be equivalent to at_c<0>(xs), and that regardless of the value category of xs (front must respect the reference semantics of at). More...
 
constexpr auto boost::hana::index_if
 Finds the value associated to the first key satisfying a predicate.Given an Iterable structure xs and a predicate pred, index_if(xs, pred) returns a hana::optional containing an IntegralConstant of the index of the first element that satisfies the predicate or nothing if no element satisfies the predicate. More...
 
constexpr auto boost::hana::is_empty
 Returns whether the iterable is empty.Given an Iterable xs, is_empty returns whether xs contains no more elements. In other words, it returns whether trying to extract the tail of xs would be an error. In the current version of the library, is_empty must return an IntegralConstant holding a value convertible to bool. This is because only compile-time Iterables are supported right now. More...
 
constexpr auto boost::hana::lexicographical_compare
 Short-circuiting lexicographical comparison of two Iterables with an optional custom predicate, by default hana::less.Given two Iterables xs and ys and a binary predicate pred, lexicographical_compare returns whether xs is to be considered less than ys in a lexicographical ordering. Specifically, let's denote the linearizations of xs and ys by [x1, x2, ...] and [y1, y2, ...], respectively. If the first couple satisfying the predicate is of the form xi, yi, lexicographical_compare returns true. Otherwise, if the first couple to satisfy the predicate is of the form yi, xi, lexicographical_compare returns false. If no such couple can be found, lexicographical_compare returns whether xs has fewer elements than ys. More...
 

Variable Documentation

◆ at

constexpr auto boost::hana::at

#include <boost/hana/fwd/at.hpp>

Initial value:
= [](auto&& xs, auto const& n) -> decltype(auto) {
return tag-dispatched;
}

Returns the nth element of an iterable.Given an Iterable and an IntegralConstant index, at returns the element located at the index in the linearization of the iterable. Specifically, given an iterable xs with a linearization of [x1, ..., xN], at(xs, k) is equivalent to xk.

If the Iterable actually stores the elements it contains, at is required to return a lvalue reference, a lvalue reference to const or a rvalue reference to the matching element, where the type of reference must match that of the iterable passed to at. If the Iterable does not store the elements it contains (i.e. it generates them on demand), this requirement is dropped.

Parameters
xsThe iterable in which an element is retrieved. The iterable must contain at least n + 1 elements.
nA non-negative IntegralConstant representing the 0-based index of the element to return. It is an error to call at with an index that out of bounds of the iterable.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
constexpr auto xs = hana::make_tuple(0, '1', 2.0);
static_assert(hana::at(xs, hana::size_t<0>{}) == 0, "");
static_assert(hana::at(xs, hana::size_t<1>{}) == '1', "");
static_assert(hana::at(xs, hana::size_t<2>{}) == 2.0, "");
int main() { }

◆ at_c

template<std::size_t n>
constexpr auto boost::hana::at_c

#include <boost/hana/fwd/at.hpp>

Initial value:
= [](auto&& xs) {
return hana::at(forwarded(xs), hana::size_c<n>);
}
constexpr auto at
Returns the nth element of an iterable.Given an Iterable and an IntegralConstant index,...
Definition: at.hpp:50

Equivalent to at; provided for convenience.

Note
hana::at_c<n> is an overloaded function, not a function object. Hence, it can't be passed to higher-order algorithms. This is done for compile-time performance reasons.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
constexpr auto xs = hana::make_tuple(0, '1', 2.0);
static_assert(hana::at_c<0>(xs) == 0, "");
static_assert(hana::at_c<1>(xs) == '1', "");
static_assert(hana::at_c<2>(xs) == 2.0, "");
int main() { }

◆ back

constexpr auto boost::hana::back

#include <boost/hana/fwd/back.hpp>

Initial value:
= [](auto&& xs) -> decltype(auto) {
return tag-dispatched;
}

Returns the last element of a non-empty and finite iterable.Given a non-empty and finite iterable xs with a linearization of [x1, ..., xN], back(xs) is equal to xN. Equivalently, back(xs) must be equivalent to at_c<N-1>(xs), and that regardless of the value category of xs (back must respect the reference semantics of at).

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
static_assert(hana::back(hana::make_tuple(1, '2', 3.3)) == 3.3, "");
static_assert(hana::back(hana::make_tuple(1, '2', 3.3, nullptr)) == nullptr, "");
int main() { }

◆ drop_front

constexpr auto boost::hana::drop_front

#include <boost/hana/fwd/drop_front.hpp>

Initial value:
= [](auto&& xs[, auto const& n]) {
return tag-dispatched;
}

Drop the first n elements of an iterable, and return the rest.Given an Iterable xs with a linearization of [x1, x2, ...] and a non-negative IntegralConstant n, drop_front(xs, n) is an iterable with the same tag as xs whose linearization is [xn+1, xn+2, ...]. In particular, note that this function does not mutate the original iterable in any way. If n is not given, it defaults to an IntegralConstant with a value equal to 1.

In case length(xs) <= n, drop_front will simply drop the whole iterable without failing, thus returning an empty iterable. This is different from drop_front_exactly, which expects n <= length(xs) but can be better optimized because of this additional guarantee.

Parameters
xsThe iterable from which elements are dropped.
nA non-negative IntegralConstant representing the number of elements to be dropped from the iterable. If n is not given, it defaults to an IntegralConstant with a value equal to 1.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
constexpr auto xs = hana::make_tuple(0, '1', 2.0);
static_assert(hana::drop_front(xs, hana::size_c<0>) == xs, "");
static_assert(hana::drop_front(xs, hana::size_c<1>) == hana::make_tuple('1', 2.0), "");
static_assert(hana::drop_front(xs, hana::size_c<2>) == hana::make_tuple(2.0), "");
BOOST_HANA_CONSTANT_CHECK(hana::drop_front(xs, hana::size_c<3>) == hana::make_tuple());
BOOST_HANA_CONSTANT_CHECK(hana::drop_front(xs, hana::size_c<4>) == hana::make_tuple());
// drop_front(xs) is equivalent to drop_front(xs, size_t<1>)
static_assert(hana::drop_front(xs) == hana::make_tuple('1', 2.0), "");
int main() { }

◆ drop_front_exactly

constexpr auto boost::hana::drop_front_exactly

#include <boost/hana/fwd/drop_front_exactly.hpp>

Initial value:
= [](auto&& xs[, auto const& n]) {
return tag-dispatched;
}

Drop the first n elements of an iterable, and return the rest.Given an Iterable xs with a linearization of [x1, x2, ...] and a non-negative IntegralConstant n, drop_front_exactly(xs, n) is an iterable with the same tag as xs whose linearization is [xn+1, xn+2, ...]. In particular, note that this function does not mutate the original iterable in any way. If n is not given, it defaults to an IntegralConstant with a value equal to 1.

It is an error to use drop_front_exactly with n > length(xs). This additional guarantee allows drop_front_exactly to be better optimized than the drop_front function, which allows n > length(xs).

Parameters
xsThe iterable from which elements are dropped.
nA non-negative IntegralConstant representing the number of elements to be dropped from the iterable. In addition to being non-negative, n must be less than or equal to the number of elements in xs. If n is not given, it defaults to an IntegralConstant with a value equal to 1.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
constexpr auto xs = hana::make_tuple(0, '1', 2.0);
static_assert(hana::drop_front_exactly(xs, hana::size_c<1>) == hana::make_tuple('1', 2.0), "");
static_assert(hana::drop_front_exactly(xs, hana::size_c<2>) == hana::make_tuple(2.0), "");
BOOST_HANA_CONSTANT_CHECK(hana::drop_front_exactly(xs, hana::size_c<3>) == hana::make_tuple());
// drop_front_exactly(xs) is equivalent to drop_front_exactly(xs, size_t<1>)
static_assert(hana::drop_front_exactly(xs) == hana::make_tuple('1', 2.0), "");
int main() { }

◆ drop_while

constexpr auto boost::hana::drop_while

#include <boost/hana/fwd/drop_while.hpp>

Initial value:
= [](auto&& iterable, auto&& predicate) {
return tag-dispatched;
}

Drop elements from an iterable up to, but excluding, the first element for which the predicate is not satisfied.Specifically, drop_while returns an iterable containing all the elements of the original iterable except for those in the range delimited by [head, e), where head is the first element and e is the first element for which the predicate is not satisfied. If the iterable is not finite, the predicate has to return a false- valued Logical at a finite index for this method to return.

Parameters
iterableThe iterable from which elements are dropped.
predicateA function called as predicate(x), where x is an element of the structure, and returning a Logical representing whether x should be dropped from the structure. In the current version of the library, predicate should return a compile-time Logical.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
using namespace hana::literals;
auto negative = [](auto x) {
return x < hana::int_c<0>;
};
hana::drop_while(hana::make_range(hana::int_c<-3>, hana::int_c<6>), negative)
==
hana::make_range(hana::int_c<0>, hana::int_c<6>)
);
hana::drop_while(hana::make_tuple(1_c, -2_c, 4_c, 5_c), negative)
==
hana::make_tuple(1_c, -2_c, 4_c, 5_c)
);
int main() { }

◆ front

constexpr auto boost::hana::front

#include <boost/hana/fwd/front.hpp>

Initial value:
= [](auto&& xs) -> decltype(auto) {
return tag-dispatched;
}

Returns the first element of a non-empty iterable.Given a non-empty Iterable xs with a linearization of [x1, ..., xN], front(xs) is equal to x1. If xs is empty, it is an error to use this function. Equivalently, front(xs) must be equivalent to at_c<0>(xs), and that regardless of the value category of xs (front must respect the reference semantics of at).

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
static_assert(hana::front(hana::make_tuple(1, '2', 3.3, nullptr)) == 1, "");
int main() { }

◆ index_if

constexpr auto boost::hana::index_if

#include <boost/hana/fwd/index_if.hpp>

Initial value:
= [](auto&& xs, auto&& predicate) {
return tag-dispatched;
}

Finds the value associated to the first key satisfying a predicate.Given an Iterable structure xs and a predicate pred, index_if(xs, pred) returns a hana::optional containing an IntegralConstant of the index of the first element that satisfies the predicate or nothing if no element satisfies the predicate.

Parameters
xsThe structure to be searched.
predicateA function called as predicate(x), where x is an element of the Iterable structure and returning whether x is the element being searched for. In the current version of the library, the predicate has to return an IntegralConstant holding a value that can be converted to bool.

Example

// Copyright Louis Dionne 2013-2017
// Copyright Jason Rice 2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
constexpr auto xs = hana::make_tuple(0, '1', 2.0);
static_assert(hana::index_if(xs, hana::is_an<int>) == hana::just(hana::size_c<0>), "");
static_assert(hana::index_if(xs, hana::is_a<char>) == hana::just(hana::size_c<1>), "");
static_assert(hana::index_if(xs, hana::is_a<double>) == hana::just(hana::size_c<2>), "");
static_assert(hana::index_if(xs, hana::is_a<hana::tuple_tag>) == hana::nothing, "");
int main() { }

◆ is_empty

constexpr auto boost::hana::is_empty

#include <boost/hana/fwd/is_empty.hpp>

Initial value:
= [](auto const& xs) {
return tag-dispatched;
}

Returns whether the iterable is empty.Given an Iterable xs, is_empty returns whether xs contains no more elements. In other words, it returns whether trying to extract the tail of xs would be an error. In the current version of the library, is_empty must return an IntegralConstant holding a value convertible to bool. This is because only compile-time Iterables are supported right now.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
BOOST_HANA_CONSTANT_CHECK(!hana::is_empty(hana::make_tuple(1, '2')));
int main() { }

◆ lexicographical_compare

constexpr auto boost::hana::lexicographical_compare

#include <boost/hana/fwd/lexicographical_compare.hpp>

Initial value:
= [](auto const& xs, auto const& ys, auto const& pred = hana::less) {
return tag-dispatched;
}
constexpr auto less
Returns a Logical representing whether x is less than y.
Definition: less.hpp:37

Short-circuiting lexicographical comparison of two Iterables with an optional custom predicate, by default hana::less.Given two Iterables xs and ys and a binary predicate pred, lexicographical_compare returns whether xs is to be considered less than ys in a lexicographical ordering. Specifically, let's denote the linearizations of xs and ys by [x1, x2, ...] and [y1, y2, ...], respectively. If the first couple satisfying the predicate is of the form xi, yi, lexicographical_compare returns true. Otherwise, if the first couple to satisfy the predicate is of the form yi, xi, lexicographical_compare returns false. If no such couple can be found, lexicographical_compare returns whether xs has fewer elements than ys.

Note
This algorithm will short-circuit as soon as it can determine that one sequence is lexicographically less than the other. Hence, it can be used to compare infinite sequences. However, for the procedure to terminate on infinite sequences, the predicate has to be satisfied at a finite index.

Signature

Given two Iterables It1(T) and It2(T) and a predicate \( pred : T \times T \to Bool \) (where Bool is some Logical), lexicographical_compare has the following signatures. For the variant with a provided predicate,

\[ \mathtt{lexicographical\_compare} : It1(T) \times It2(T) \times (T \times T \to Bool) \to Bool \]

for the variant without a custom predicate, T is required to be Orderable. The signature is then

\[ \mathtt{lexicographical\_compare} : It1(T) \times It2(T) \to Bool \]

Parameters
xs,ysTwo Iterables to compare lexicographically.
predA binary function called as pred(x, y) and pred(y, x), where x and y are elements of xs and ys, respectively. pred must return a Logical representing whether its first argument is to be considered as less than its second argument. Also note that pred must define a total ordering as defined by the Orderable concept. When pred is not provided, it defaults to less.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
int main() {
// works with elements whose `less` does not return a Constant
{
constexpr auto xs = hana::make_tuple(1, 2, 3, 4);
constexpr auto ys = hana::make_tuple(1, 6, 3, 4);
static_assert(hana::lexicographical_compare(xs, ys), "");
}
// and with those that do
{
auto xs = hana::make_tuple(hana::int_c<1>, hana::int_c<2>, hana::int_c<3>);
auto ys = hana::make_tuple(hana::int_c<1>, hana::int_c<5>, hana::int_c<3>);
}
// it also accepts a custom predicate
{
auto xs = hana::make_tuple(hana::type_c<int>, hana::type_c<char>, hana::type_c<void*>);
auto ys = hana::make_tuple(hana::type_c<int>, hana::type_c<long>, hana::type_c<void*>);
hana::lexicographical_compare(xs, ys, [](auto t, auto u) {
return hana::sizeof_(t) < hana::sizeof_(u);
})
);
}
}