Repetition Generator Directive (repeat[])

| Home | Libraries | People | FAQ | More

##### Repetition Generator Directive (`repeat[]`)

###### Description

The repetition directive allows to repeat an arbitrary generator expression while optionally specifying the lower and upper repetition counts. It provides a more powerful and flexible mechanism for repeating a generator. There are grammars that are impractical and cumbersome, if not impossible, for the basic EBNF iteration syntax ( unary `'*'` and the unary `'+'`) to specify. Examples:

- A file name may have a maximum of 255 characters only.
- A specific bitmap file format has exactly 4096 RGB color information.
- A 256 bit binary string (1..256 1s or 0s).

###### Header

    // forwards to <boost/spirit/home/karma/directive/repeat.hpp>
    #include <boost/spirit/include/karma_repeat.hpp>

Also, see Include Structure.

###### Namespace

Name
`boost::spirit::repeat // alias: boost::spirit::karma::repeat`
`boost::spirit::inf // alias: boost::spirit::karma::inf`

###### Model of

> `UnaryGenerator`

Notation

`a`

  A generator object

`num, num1, num2`

  Numeric literals, any unsigned integer value, or a Lazy Argument that evaluates to an unsigned integer value

`inf`

  Placeholder expression standing for 'no upper repeat limit'

###### Expression Semantics

Semantics of an expression is defined only where it differs from, or is not defined in `UnaryGenerator`.

Expression | Semantics
--- | ---
`repeat[a]` | Repeat the generator `a` zero or more times. This generator succeeds as long as its embedded generator `a` does not fail (except if the underlying output stream reports an error). This variant of `repeat[]` is semantically equivalent to the Kleene Star operator `*a`
`repeat(num)[a]` | Repeat the generator `a` exactly `num` times. This generator succeeds as long as its embedded generator `a` does not fail and as long as the associated attribute (container) contains at least `num` elements (unless the underlying output stream reports an error).
`repeat(num1, num2)[a]` | Repeat the generator `a` at least `num1` times but not more than `num2` times. This generator succeeds as long as its embedded generator `a` does not fail and as long as the associated attribute (container) contains at least `num1` elements (unless the underlying output stream reports an error). If the associated attribute (container) does contain more than `num2` elements, this directive limits the repeat count to `num2`.
`repeat(num, inf)[a]` | Repeat the generator `a` at least `num1` times. No upper limit for the repeat count is set. This generator succeeds as long as its embedded generator `a` does not fail and as long as the associated attribute (container) contains at least `num` elements (unless the underlying output stream reports an error).

| Note
All failing iterations of the embedded generator will consume one element from the supplied attribute. The overall `repeat[a]` will succeed as long as the iteration criteria (number of successful invocations of the embedded generator) is fulfilled (unless the underlying output stream reports an error).

###### Attributes

See Compound Attribute Notation.

Expression | Attribute
--- | ---
`repeat[a]` |
    a: A --> repeat[a]: vector<A>
    a: Unused --> repeat[a]: Unused
`repeat(num)[a]` |
    a: A --> repeat(num)[a]: vector<A>
    a: Unused --> repeat(num)[a]: Unused
`repeat(num1, num2)[a]` |
    a: A --> repeat(num1, num2)[a]: vector<A>
    a: Unused --> repeat(num1, num2)[a]: Unused
`repeat(num, inf)[a]` |
    a: A --> repeat(num, inf)[a]: vector<A>
    a: Unused --> repeat(num, inf)[a]: Unused

| Important
The table above uses `vector<A>` as placeholders only. The notation of `vector<A>` stands for any STL container holding elements of type `A`.

It is important to note, that the `repeat[]` directive does not perform any buffering of the output generated by its embedded elements. That means that any failing element generator might have already generated some output, which is not rolled back.

| Tip
The simplest way to force a `repeat[]` directive to behave as if it did buffering is to wrap it into a buffering directive (see `buffer`):
    buffer[repeat[a]]
which will not generate any output in case of a failing generator `repeat[a]`. The expression:
    repeat[buffer[a]]
will not generate any partial output from a generator `a` if it fails generating in the middle of its output. The overall expression will still generate the output as produced by all succeeded invocations of the generator `a`.

###### Complexity

> The overall complexity of the repetition generator is defined by the complexity of its embedded generator. The complexity of the repeat itself is O(N), where N is the number of repetitions to execute.

###### Example

| Note
The test harness for the example(s) below is presented in the Basics Examples section.

Some includes:

    #include <boost/spirit/include/karma.hpp>
    #include <boost/spirit/include/support_utree.hpp>
    #include <boost/phoenix/core.hpp>
    #include <boost/phoenix/operator.hpp>
    #include <boost/fusion/include/std_pair.hpp>
    #include <boost/proto/deep_copy.hpp>
    #include <iostream>
    #include <string>

Some using declarations:

    using boost::spirit::karma::double_;
    using boost::spirit::karma::repeat;

Basic usage of `repeat` generator directive:

    std::vector<double> v;
    v.push_back(1.0);
    v.push_back(2.0);
    v.push_back(3.0);

    test_generator_attr("[1.0][2.0][3.0]", repeat['[' << double_ << ']'], v);
    test_generator_attr("[1.0][2.0]", repeat(2)['[' << double_ << ']'], v);

    // fails because of insufficient number of items
    test_generator_attr("", repeat(4)['[' << double_ << ']'], v);