All constructions described on this page are similar in that they take one or more container objects and produce a new object which behaves like a container too, but is not a container in the strict sense: it does not own any data. We will call them pseudo-container throughout this documentation.
The pseudo-containers can be divided in three categories according to their functionality:
front(), back(),
or operator[]) or reside in the iterator. Traversing a lazy container object multiple times object incurs
repeating computations, which should be kept in mind when sticking it into a multi-pass algorithm template.
When you write an algorithm template, you can make it safe from multiple evaluation of lazy objects using the following construction:
typename prevent_lazy<Object>::type X=prevent_lazy<Object>::get(x);
where x is an input parameter and Object its type. If Object is really lazy, it performs the evaluation exactly once and stores the results in an appropriate persistent object; if not, it does nothing.
protected and left undefined.
To make the classification complete, let's call the standard containers, whose lifetime is the same as of their elements, persistent. This notion is traditionally used in the context of data base query languages, where it describes objects that can outlive the programs creating them. This is also applicable to objects in Polymake Template Library, since they can be stored in and retrieved from the data file via the client-server communication interface without any loss in structure or contents.
For instantiatable pseudo-containers (alias and lazy) it is important to know how to find the original data containers. Generally, the latter have a lifetime much longer than a pseudo-container object, which in the most cases exists during exactly one expression. Thus an internal reference to the original object would be sufficient.
On the other hand, the pseudo-containers are easy to combine and nest (it was, after all, the main design aim to made them interchangeable building blocks!) For example, one can first select a subset of elements and then apply an operation to it. In this case, the first operand of the outer pseudo-container will be the inner pseudo-container, which in its turn is a temporary object. It doesn't comprise a problem until the entire construction is copied outside the scope the components are confined to.
The best example is a return statement: if a function has to return the outer pseudo-container object,
it may not contain a reference to the inner object, since it was created in the function's scope and will
be destroyed after the return completion. Therefore the inner object must be copied into the
outer object.
All pseudo-container objects in the Polymake Template Library can be configured for both scenarios. The template parameters
describing the data sources are optional references: they can be specified as references
as well as reference-free data types. Note that the convenience functions always create pseudo-containers with
internal references, as a more efficient and more often occuring variant; the referenceless variant should be used only
when it's really necessary, like in the return context explained above.
<IndexedSubset.h>
It is automatically included together with all top-level data structures.
<SelectedSubset.h>
const attribute from the corresponding function argument.
A pseudo-container with a const reference to the source data is in its turn immutable.
The constructions in this section select a subset from a data container (real or pseudo)
according to some choice criterion.
All they belong to the alias type.
Assigning a new value to an element effectively changes the contents in the original data container.
Pseudo-containers with first argument having const attribute are immutable.
GenericSet or a complement thereof,
the selected elements keep their order in the data container, and thus preserve the GenericSet
property of the DataContainer, if any. On the other hand, the index sequence may be not increasing,
not monotonic, or even contain repeating indices, which would let the corresponding data element appear
multiple times.
IndexedSubset and IndexedSlice is in the handling of sparse containers:
the elements in the former preserve their indices from the original data container, while in the latter they are renumbered
to the index positions in IndexContainer.
bool or convertible to it. Only elements evaluated to true show up in the
pseudo-container, the rest is hidden. The selected elements preserve their order from the the data container.
size() method runs thru entire container, while empty() until the first
true hit.
SelectedSubset described above, but the predicate evaluation stops at
the first false result. With other words, the visible element subrange starts always at the
beginning of the data container and ends before the first element mapped to false.
SelectedSubset described above, but with a binary functor as a predicate.
The second container argument serves solely as the predicate second operand source, the visible elements are
those from DataContainer. The elements of both containers are taken pairwise for the evaluation, therefore
their sizes must be equal.
size() method runs thru entire container, while empty() until the first
true hit.
bool or convertible to it) serve as visibility mask bits for the corresponding elements of the data
container. Both containers must be of equal size.
The random subset selection would fit in this category too.
<TransformedContainer.h>
It is automatically included together with all top-level data structures.
TransformedContainerPair<const Container&, const unlimited_constant_container<Scalar>&,
BuildBinary<operations::add> >
TransformedContainerPair<const Container&, const unlimited_constant_container<Scalar>&,
BuildBinary<operations::mul> >
The constructions in this section perform an operation encoded as a unary or binary functor on the elements of the given input data container(s) and show the results as apparent elements. They are lazy containers.
int -> double), user-defined (constructor without explicit attribute,
conversion operator), or encoded as a specialization of conv class.
<CascadedContainer.h>
It is automatically included together with all matrix classes.
<ContainerChain.h>
It is automatically included together with all matrix and vector classes.
const attribute from the corresponding function argument.
A pseudo-container with at least one const reference to the source data is in its turn immutable.
begin() and end() with rbegin() and rend()
and so on. Clearly, the input container must be reversible.
object_traits.)
size() need to traverse all intermediate layers in order to count all elements.
cascade<depth>(Container), but
this is currently not applicable due to a obscure compiler bug. Thus we must put up with int2type
wrapper.
ContainerUnion. You might need to wrap one component
in a converting TransformedContainer, if you find this more
suitable than handling with type_union objects.
The random permutation would fit in this category too.