C++QEDCore  2.100.2 (v2 Milestone 10 Development branch)
a framework for simulating open quantum dynamics – core
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Notes on the implementation of Iterator

Table of Contents

Transposer and Indexer are implemented in such a way that a partial template specialization is provided for each possible RANK (up to BLITZ_ARRAY_LARGEST_RANK), and the corresponding code is automatically generated by the Boost.Preprocessor library. This can be seen in the trailing part of BlitzArraySliceIterator.tcc. To actually see what code is generated, this file needs to be preprocessed. Issue the following command from the root directory of the distribution:

1 g++ -P -E -Iutils/ utils/BlitzArraySliceIterator.tcc | tail -n286

To store and manipulate the heterogenous collection of slicing indices like 0,a,2,a,4,5,a,a,8,a,10 in Indexer::index, the vector class of the Boost.Fusion library is used.

Iterator is implemented in terms of the above two helper classes. Each Iterator invokes a Transposer::transpose at its construction, and – if RANK is larger than Size<V>::value – an Indexer::index @ the point of its dereferencing when the actual slicing occurs.

Iterator is a forward iterator, implemented with the help of forward_iterator_helper from Boost.Operator. For this to work, we need to define only 3 operations:

  1. Comparison for equality
  2. Prefix increment
  3. Dereferencing A special implementation is needed when the size of the compile-time vector V equals RANK because in this case actually no slicing takes place, only transposition. For this, as at several other places in the framework, we apply conditional inheritance: Iterator inherits from either of two classes (details::Base or details::BaseSpecial), the decision being made @ compile time with the help of boost::mpl::if_c.

The iteration over dummy indices is implemented with the help of cpputils::MultiIndexIterator.

A metaprogramming example

In the following we analyse a metaprogramming example typical for the framework: how the compile-time vector 0,3,2,6,4,5,1,9,8,7,10 for the self-transposition in Transposer::transpose is prepared.

This is done by the following snippet in utils/BlitzArraySliceIterator.tcc:

namespace namehider {
using namespace boost::mpl;
namespace mpl=boost::mpl;
using namespace tmptools;
template<int RANK, typename V>
struct Algorithm
: fold<Ordinals<RANK>,
We are using the fold metaalgorithm from Boost.MPL. Here, it iterates over the sequence of ordinals (tmptools::Ordinals) between 0 and RANK-1.
pair<vector_c<int>,typename boost::mpl::begin<V>::type>,
The initial state for the fold algorithm is an empty compile-time vector of integers and the iterator pointing to the first element of the compile-time vector V. These two are “zipped” into a compile-time pair. At the end, the first element of this pair will hold the result.

The rest expresses the forward operation of the fold algorithm in the form of a compile-time lambda expression. After each step, the new state will again be a pair composed of

pair<push_back<mpl::first<mpl::_1>,
if_<numerical_contains<V,mpl::_2>,
deref<second<mpl::_1> >,
mpl::_2
>
>,
i. the vector is augmented either by the current element in V pointed to by the iterator (Line 13), or the current ordinal (Line 14), depending on whether V tmptools::numerical_contains this ordinal.
if_<numerical_contains<V,mpl::_2>,
mpl::next<second<mpl::_1> >,
second<mpl::_1>
>
ii. the iterator is advanced (Line 18) if the same numerical containment criterion is met, otherwise it is left untouched for the same element to be considered again (Line 19).

Note
In template metaprogramming, “calling” tmptools::numerical_contains<V,mpl::_2> twice is no waste because the second time no further template instantiations are needed, the compiler will use the ones already instantiated the first time.

>
>
{};
} // namehider
template<int RANK, typename V>
struct TransposerMeta : boost::mpl::first<typename namehider::Algorithm<RANK,V>::type>
{};
the first element of the resulting pair of the above algorithm is picked. As it is easy to verify,

TransposerMeta<11,tmptools::Vector<3,6,1,9,7> >::type

will be an

mpl::vector_c<int,0,3,2,6,4,5,1,9,8,7,10>