Increment the Iterator pointing into a Container Attribute

| Home | Libraries | People | FAQ | More

##### Increment the Iterator pointing into a Container Attribute

###### next_iterator

The template `next_iterator` is a type used as an attribute customization point. It is invoked by the Karma repetitive generators (such as List (`%`), Kleene (unary `*`), Plus (unary `+`), and Repeat) in order to get an iterator pointing to the next element of a container holding the attributes to generate output from.

###### Module Headers

    #include <boost/spirit/home/support/container.hpp>

Also, see Include Structure.

| Note
This header file does not need to be included directly by any user program as it is normally included by other Spirit header files relying on its content.

###### Namespace

Name
`boost::spirit::traits`

###### Synopsis

    template <typename Iterator, typename Enable>
    struct next_iterator
    {
        static void call(Iterator& it);
    };

###### Template parameters

Parameter | Description | Default
--- | --- | ---
`Iterator` | The type, `Iterator` of the iterator to increment. This is the same as the type returned by the customization point `traits::container_iterator`. | none
`Enable` | Helper template parameter usable to selectively enable or disable certain specializations of `next_iterator` utilizing SFINAE (i.e. `boost::enable_if` or `boost::disable_if`). | `void`

Notation

`Iterator`

  An iterator type.

`it`

  An instance of an iterator of type `Iterator`.

`C`

  A container type whose iterator type is `Iterator`.

###### Expression Semantics

Expression | Semantics
--- | ---
`next_iterator<Iterator>::call(it)` | Increment the iterator pointing so that it is pointing to the next element.

###### Predefined Specializations

Spirit predefines specializations of this customization point for several types. The following table lists those types together with the types returned by the embedded typedef `type`:

Template Parameters | Semantics
--- | ---
`Iterator` | Executes `++it`.
`unused_type` `const*` | Does nothing.

###### When to implement

The customization point `next_iterator` needs to be implemented for a specific iterator type whenever the container this iterator belongs to is to be used as an attribute in place of a STL container. It is applicable for generators (Spirit.Karma) only. As a rule of thumb: it has to be implemented whenever a certain iterator type belongs to a container which is to be passed as an attribute to a generator normally exposing a STL container, `C` and if the container type does not expose the interface of a STL container (i.e. `is_container<C>::type` would normally return `mpl::false_`).

###### Related Attribute Customization Points

If this customization point is implemented, the following other customization points might need to be implemented as well.

Name | When to implement
--- | ---
`traits::is_container` | Needs to be implemented whenever a type is to be used as a container attribute in Karma.
`traits::container_iterator` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.
`traits::begin_container` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.
`traits::end_container` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.
`traits::deref_iterator` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.
`traits::next_iterator` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.
`traits::compare_iterators` | Karma: List (`%`), Kleene (unary `*`), Plus (unary `+`), Repeat.

###### Example

Here are the header files needed to make the example code below compile:

    #include <boost/spirit/include/karma.hpp>
    #include <iostream>
    #include <string>
    #include <vector>

The example (for the full source code please see here: customize_use_as_container.cpp) uses the data structure

    namespace client
    {
        struct use_as_container
        {
            // Expose a pair holding a pointer to the use_as_container and to the
            // current element as our iterator.
            // We intentionally leave out having it a 'operator==()' to demonstrate
            // the use of the 'compare_iterators' customization point.
            struct iterator
            {
                iterator(use_as_container const* container, int const* current)
                  : container_(container), current_(current)
                {}

                use_as_container const* container_;
                int const* current_;
            };

            // expose 'int' as the type of each generated element
            typedef int type;

            use_as_container(int value1, int value2, int value3)
              : value1_(value1), value2_(value2), value3_(value3)
            {}

            int value1_;
            std::string dummy1_;    // insert some unrelated data
            int value2_;
            std::string dummy2_;    // insert some more unrelated data
            int value3_;
        };
    }

as a direct attribute to the List (`%`) generator. This type does not expose any of the interfaces of an STL container. It does not even expose the usual semantics of a container. The purpose of this artificial example is to demonstrate how the customization points can be used to expose independent data elements as a single container. The example shows how to enable its use as an attribute to Karma's repetitive generators.

In order to make this data structure compatible we need to specialize a couple of attribute customization points: `traits::is_container`, `traits::container_iterator`, `traits::begin_container`, and `traits::end_container`. In addition, we specialize all of the iterator related customization points as well: `traits::deref_iterator`, `traits::next_iterator`, and `traits::compare_iterators`.

    // All specializations of attribute customization points have to be placed into
    // the namespace boost::spirit::traits.
    //
    // Note that all templates below are specialized using the 'const' type.
    // This is necessary as all attributes in Karma are 'const'.
    namespace boost { namespace spirit { namespace traits
    {
        // The specialization of the template 'is_container<>' will tell the
        // library to treat the type 'client::use_as_container' as a
        // container holding the items to generate output from.
        template <>
        struct is_container<client::use_as_container const>
          : mpl::true_
        {};

        // The specialization of the template 'container_iterator<>' will be
        // invoked by the library to evaluate the iterator type to be used
        // for iterating the data elements in the container. We simply return
        // the type of the iterator exposed by the embedded 'std::vector<int>'.
        template <>
        struct container_iterator<client::use_as_container const>
        {
            typedef client::use_as_container::iterator type;
        };

        // The specialization of the templates 'begin_container<>' and
        // 'end_container<>' below will be used by the library to get the iterators
        // pointing to the begin and the end of the data to generate output from.
        //
        // The passed argument refers to the attribute instance passed to the list
        // generator.
        template <>
        struct begin_container<client::use_as_container const>
        {
            static client::use_as_container::iterator
            call(client::use_as_container const& c)
            {
                return client::use_as_container::iterator(&c, &c.value1_);
            }
        };

        template <>
        struct end_container<client::use_as_container const>
        {
            static client::use_as_container::iterator
            call(client::use_as_container const& c)
            {
                return client::use_as_container::iterator(&c, (int const*)0);
            }
        };
    }}}

    // All specializations of attribute customization points have to be placed into
    // the namespace boost::spirit::traits.
    namespace boost { namespace spirit { namespace traits
    {
        // The specialization of the template 'deref_iterator<>' will be used to
        // dereference the iterator associated with our counter data structure.
        template <>
        struct deref_iterator<client::use_as_container::iterator>
        {
            typedef client::use_as_container::type type;

            static type call(client::use_as_container::iterator const& it)
            {
                return *it.current_;
            }
        };

        template <>
        struct next_iterator<client::use_as_container::iterator>
        {
            static void call(client::use_as_container::iterator& it)
            {
                if (it.current_ == &it.container_->value1_)
                    it.current_ = &it.container_->value2_;
                else if (it.current_ == &it.container_->value2_)
                    it.current_ = &it.container_->value3_;
                else
                    it.current_ = 0;
            }
        };

        template <>
        struct compare_iterators<client::use_as_container::iterator>
        {
            static bool call(client::use_as_container::iterator const& it1
              , client::use_as_container::iterator const& it2)
            {
                return it1.current_ == it2.current_ &&
                       it1.container_ == it2.container_;
            }
        };
    }}}

The last code snippet shows an example using an instance of the data structure `client::use_as_container` to generate output from a List (`%`) generator:

    client::use_as_container d2 (1, 2, 3);
    // use the instance of a 'client::use_as_container' instead of a STL vector
    std::cout << karma::format(karma::int_ % ", ", d2) << std::endl;   // prints: '1, 2, 3'

As you can see, the specializations for the customization points as defined above enable the seamless integration of the custom data structure without having to modify the output format or the generator itself.