set -> seq

[SVN r16151]
This commit is contained in:
Paul Mensonides
2002-11-07 23:41:54 +00:00
parent 5be4c6ee5a
commit 91eba2f11b
2 changed files with 205 additions and 168 deletions

View File

@ -558,10 +558,10 @@ for (int i = start(1); i <= finish(1); ++i) {
<div>
The library also provides macros to access values in dimensions <i>relative</i>
to the current dimension (e.g. the <i>previous</i> dimension).&nbsp; These
macros take an argument that is interpreted as an offseq from the current
macros take an argument that is interpreted as an offset from the current
frame.&nbsp; For example, <b>BOOST_PP_RELATIVE_ITERATION</b>(<i>1</i>) always
refers to the outer dimension immediately previous to the current
dimension.&nbsp; An argument of <i>0</i> is interpreted as an offseq of <i>0</i>
dimension.&nbsp; An argument of <i>0</i> is interpreted as an offset of <i>0</i>
which causes <b>BOOST_PP_RELATIVE_ITERATION</b>(<i>0</i>) to be equivalent to <b>BOOST_PP_ITERATION</b>().&nbsp;
<b>BOOST_PP_RELATIVE_ITERATION</b>(<i>2</i>) refers to the iteration value of
the dimension immediately preceding the dimension that precedes the current

View File

@ -4,40 +4,48 @@
<link rel="stylesheet" type="text/css" href="../styles.css">
</head>
<body>
<h4>Reentrancy</h4>
<h4>
Reentrancy
</h4>
<div>
Macro expansion in the preprocessor is entirely functional.&nbsp;
Therefore, there is no iteration.&nbsp;
Unfortunately, the preprocessor also disallows recursion.&nbsp;
This means that the library must fake iteration or recursion by
defining sets of macros that are implemented similarly.&nbsp;
Macro expansion in the preprocessor is entirely functional.&nbsp; Therefore,
there is no iteration.&nbsp; Unfortunately, the preprocessor also disallows
recursion.&nbsp; This means that the library must fake iteration or recursion
by defining seqs of macros that are implemented similarly.&nbsp;
</div>
<div>
To illustrate, here is a simple concatenation macro:
</div>
<div class="code"><pre>
<div class="code">
<pre>
#define CONCAT(a, b) CONCAT_D(a, b)
#define CONCAT_D(a, b) a ## b
CONCAT(a, CONCAT(b, c)) // abc
</pre></div>
<div>
This is fine for a simple case like the above, but what happens in a scenario like the following:
</pre>
</div>
<div class="code"><pre>
<div>
This is fine for a simple case like the above, but what happens in a scenario
like the following:
</div>
<div class="code">
<pre>
#define AB(x, y) CONCAT(x, y)
CONCAT(A, B(p, q)) // CONCAT(p, q)
</pre></div>
<div>
Because there is no recursion, the example above expands to <code>CONCAT(p, q)</code> rather than <code>pq</code>.
</pre>
</div>
<div>
There are only two ways to "fix" the above.&nbsp;
First, it can be documented that <code>AB</code> uses <code>CONCAT</code> and disallow usage similar to the above.&nbsp;
Second, multiple concatenation macros can be provided....
Because there is no recursion, the example above expands to <code>CONCAT(p, q)</code>
rather than <code>pq</code>.
</div>
<div class="code"><pre>
<div>
There are only two ways to "fix" the above.&nbsp; First, it can be documented
that <code>AB</code> uses <code>CONCAT</code> and disallow usage similar to the
above.&nbsp; Second, multiple concatenation macros can be provided....
</div>
<div class="code">
<pre>
#define CONCAT_1(a, b) CONCAT_1_D(a, b)
#define CONCAT_1_D(a, b) a ## b
@ -47,68 +55,80 @@ CONCAT(A, B(p, q)) // CONCAT(p, q)
#define AB(x, y) CONCAT_2(x, y)
CONCAT_1(A, B(p, q)) // pq
</pre></div>
</pre>
</div>
<div>
This solves the problem.&nbsp;
However, it is now necessary to know that <code>AB</code> uses, not only <i>a</i> concatenation macro,
but <code>CONCAT_2</code> specifically.
This solves the problem.&nbsp; However, it is now necessary to know that <code>AB</code>
uses, not only <i>a</i> concatenation macro, but <code>CONCAT_2</code> specifically.
</div>
<div>
A better solution is to abstract <i>which</i> concatenation macro is used....
</div>
<div class="code"><pre>
<div class="code">
<pre>
#define AB(c, x, y) CONCAT_ ## c(x, y)
CONCAT_1(A, B(2, p, q)) // pq
</pre></div>
<div>
This is an example of <i>generic reentrance</i>, in this case, into a fictional set of concatenation macros.&nbsp;
The <code>c</code> parameter represents the "state" of the concatenation construct,
and as long as the user keeps track of this state, <code>AB</code> can be used inside of a concatenation macro.
</pre>
</div>
<div>
The library has the same choices.&nbsp;
It either has to disallow a construct being inside itself or provide multiple, equivalent definitions of a construct
and provide a uniform way to <i>reenter</i> that construct.&nbsp;
There are several contructs that <i>require</i> recursion (such as <b>BOOST_PP_WHILE</b>).&nbsp;
Consequently, the library chooses to provide several sets of macros with mechanisms to reenter the set at a macro
that has not already been used.
This is an example of <i>generic reentrance</i>, in this case, into a fictional
seq of concatenation macros.&nbsp; The <code>c</code> parameter represents the
"state" of the concatenation construct, and as long as the user keeps track of
this state, <code>AB</code> can be used inside of a concatenation macro.
</div>
<div>
In particular, the library must provide reentrance for <b>BOOST_PP_FOR</b>, <b>BOOST_PP_REPEAT</b>, and <b>BOOST_PP_WHILE</b>.&nbsp;
There are two mechanisms that are used to accomplish this:&nbsp; state parameters (like the above concatenation example) and <i>automatic recursion</i>.
</div>
<h4>State Parameters</h4>
<div>
Each of the above constructs (<b>BOOST_PP_FOR</b>, <b>BOOST_PP_REPEAT</b>, and <b>BOOST_PP_WHILE</b>) has an associated state.&nbsp;
This state provides the means to reenter the respective construct.
The library has the same choices.&nbsp; It either has to disallow a construct
being inside itself or provide multiple, equivalent definitions of a construct
and provide a uniform way to <i>reenter</i> that construct.&nbsp; There are
several contructs that <i>require</i> recursion (such as <b>BOOST_PP_WHILE</b>).&nbsp;
Consequently, the library chooses to provide several seqs of macros with
mechanisms to reenter the seq at a macro that has not already been used.
</div>
<div>
Several user-defined macros are passed to each of these constructs (for use as predicates, operations, etc.).&nbsp;
Every time a user-defined macro is invoked, it is passed the current state of the construct that invoked it so that the macro can reenter
the respective set if necessary.
In particular, the library must provide reentrance for <b>BOOST_PP_FOR</b>, <b>BOOST_PP_REPEAT</b>,
and <b>BOOST_PP_WHILE</b>.&nbsp; There are two mechanisms that are used to
accomplish this:&nbsp; state parameters (like the above concatenation example)
and <i>automatic recursion</i>.
</div>
<h4>
State Parameters
</h4>
<div>
Each of the above constructs (<b>BOOST_PP_FOR</b>, <b>BOOST_PP_REPEAT</b>, and <b>BOOST_PP_WHILE</b>)
has an associated state.&nbsp; This state provides the means to reenter the
respective construct.
</div>
<div>
These states are used in one of two ways--either by concatenating to or passing to another macro.
Several user-defined macros are passed to each of these constructs (for use as
predicates, operations, etc.).&nbsp; Every time a user-defined macro is
invoked, it is passed the current state of the construct that invoked it so
that the macro can reenter the respective seq if necessary.
</div>
<div>
There are three types of macros that use these state parameters.&nbsp;
First, the set itself which is reentered through concatenation.&nbsp;
Second, corresponding sets that act like they are a part of the the primary set.&nbsp;
These are also reentered through concatenation.&nbsp;
And third, macros that internally use the first or second type of macro.&nbsp;
These macros take the state as an additional argument.
These states are used in one of two ways--either by concatenating to or passing
to another macro.
</div>
<div>
There are three types of macros that use these state parameters.&nbsp; First,
the seq itself which is reentered through concatenation.&nbsp; Second,
corresponding seqs that act like they are a part of the the primary seq.&nbsp;
These are also reentered through concatenation.&nbsp; And third, macros that
internally use the first or second type of macro.&nbsp; These macros take the
state as an additional argument.
</div>
<div>
The state of <b>BOOST_PP_WHILE</b> is symbolized by the letter <i>D</i>.&nbsp;
Two user-defined macros are passed to <b>BOOST_PP_WHILE</b>--a predicate and an operation.&nbsp;
When <b>BOOST_PP_WHILE</b> expands these macros, it passes along its state so that these macros
can reenter the <b>BOOST_PP_WHILE</b> set.&nbsp;
Two user-defined macros are passed to <b>BOOST_PP_WHILE</b>--a predicate and an
operation.&nbsp; When <b>BOOST_PP_WHILE</b> expands these macros, it passes
along its state so that these macros can reenter the <b>BOOST_PP_WHILE</b> seq.&nbsp;
</div>
<div>
Consider the following multiplication implementation that illustrates this technique:
Consider the following multiplication implementation that illustrates this
technique:
</div>
<div class="code"><pre>
<div class="code">
<pre>
// The addition interface macro.
// The _D signifies that it reenters
// BOOST_PP_WHILE with concatenation.
@ -175,79 +195,96 @@ CONCAT_1(A, B(2, p, q)) // pq
/**/
MUL(3, 2) // expands to 6
</pre></div>
</pre>
</div>
<div>
There are a couple things to note in the above implementation.&nbsp;
First, note how <code>ADD_D</code> reenters <b>BOOST_PP_WHILE</b> using the <i>d</i> state parameter.&nbsp;
Second, note how <code>MUL</code>'s operation, which is expanded by <b>BOOST_PP_WHILE</b>, passes the state
on to <code>ADD_D</code>.&nbsp;
There are a couple things to note in the above implementation.&nbsp; First,
note how <code>ADD_D</code> reenters <b>BOOST_PP_WHILE</b> using the <i>d</i> state
parameter.&nbsp; Second, note how <code>MUL</code>'s operation, which is
expanded by <b>BOOST_PP_WHILE</b>, passes the state on to <code>ADD_D</code>.&nbsp;
This illustrates state reentrance by both argument and concatenation.
</div>
<div>
For every macro in the library that uses <b>BOOST_PP_WHILE</b>,
there is a state reentrant variant.&nbsp;
If that variant uses an argument rather than concatenation, it is suffixed by <code>_D</code> to symbolize its
method of reentrance.&nbsp;
Examples or this include the library's own <b>BOOST_PP_ADD_D</b> and <b>BOOST_PP_MUL_D</b>.&nbsp;
If the variant uses concatenation, it is suffixed by an underscore.&nbsp;
It is completed by concatenation of the state.&nbsp;
This includes <b>BOOST_PP_WHILE</b> itself with <b>BOOST_PP_WHILE_</b> ## <i>d</i> and, for example,
<b>BOOST_PP_LIST_FOLD_LEFT</b> with <b>BOOST_PP_LIST_FOLD_LEFT_</b> ## <i>d</i>.
For every macro in the library that uses <b>BOOST_PP_WHILE</b>, there is a
state reentrant variant.&nbsp; If that variant uses an argument rather than
concatenation, it is suffixed by <code>_D</code> to symbolize its method of
reentrance.&nbsp; Examples or this include the library's own <b>BOOST_PP_ADD_D</b>
and <b>BOOST_PP_MUL_D</b>.&nbsp; If the variant uses concatenation, it is
suffixed by an underscore.&nbsp; It is completed by concatenation of the
state.&nbsp; This includes <b>BOOST_PP_WHILE</b> itself with <b>BOOST_PP_WHILE_</b>
## <i>d</i> and, for example, <b>BOOST_PP_LIST_FOLD_LEFT</b> with <b>BOOST_PP_LIST_FOLD_LEFT_</b>
## <i>d</i>.
</div>
<div>
The same set of conventions are used for <b>BOOST_PP_FOR</b> and <b>BOOST_PP_REPEAT</b>, but with the letters
<i>R</i> and <i>Z</i>, respectively, to symbolize their states.
The same seq of conventions are used for <b>BOOST_PP_FOR</b> and <b>BOOST_PP_REPEAT</b>,
but with the letters <i>R</i> and <i>Z</i>, respectively, to symbolize their
states.
</div>
<div>
Also note that the above <code>MUL</code> implementation, though not immediately obvious, is using <i>all three</i>
types of reentrance.&nbsp;
Not only is it using both types of <i>state</i> reentrance, it is also using <i>automatic recursion</i>....
Also note that the above <code>MUL</code> implementation, though not
immediately obvious, is using <i>all three</i> types of reentrance.&nbsp; Not
only is it using both types of <i>state</i> reentrance, it is also using <i>automatic
recursion</i>....
</div>
<h4>Automatic Recursion</h4>
<h4>
Automatic Recursion
</h4>
<div>
Automatic recursion is a technique that vastly simplifies the use of reentrant constructs.&nbsp;
It is used by simply <i>not</i> using any state parameters at all.
Automatic recursion is a technique that vastly simplifies the use of reentrant
constructs.&nbsp; It is used by simply <i>not</i> using any state parameters at
all.
</div>
<div>
The <code>MUL</code> example above uses automatic recursion when it uses <b>BOOST_PP_WHILE</b> by itself.&nbsp;
In other words, <code>MUL</code> can <i>still</i> be used inside <b>BOOST_PP_WHILE</b> even though it doesn't
reenter <b>BOOST_PP_WHILE</b> by concatenating the state to <b>BOOST_PP_WHILE_</b>.
The <code>MUL</code> example above uses automatic recursion when it uses <b>BOOST_PP_WHILE</b>
by itself.&nbsp; In other words, <code>MUL</code> can <i>still</i> be used
inside <b>BOOST_PP_WHILE</b> even though it doesn't reenter <b>BOOST_PP_WHILE</b>
by concatenating the state to <b>BOOST_PP_WHILE_</b>.
</div>
<div>
To accomplish this, the library uses a "trick."&nbsp;
Despite what it looks like, the macro <b>BOOST_PP_WHILE</b> does not take three arguments.&nbsp;
In fact, it takes no arguments at all.&nbsp;
Instead, the <b>BOOST_PP_WHILE</b> macro expands <i>to</i> a macro that takes three arguments.&nbsp;
It simply detects what the next available <b>BOOST_PP_WHILE_</b> ## <i>d</i> macro is and returns it.&nbsp;
This detection process is somewhat involved, so I won't go into <i>how</i> it works here,
but suffice to say it <i>does</i> work.
To accomplish this, the library uses a "trick."&nbsp; Despite what it looks
like, the macro <b>BOOST_PP_WHILE</b> does not take three arguments.&nbsp; In
fact, it takes no arguments at all.&nbsp; Instead, the <b>BOOST_PP_WHILE</b> macro
expands <i>to</i> a macro that takes three arguments.&nbsp; It simply detects
what the next available <b>BOOST_PP_WHILE_</b> ## <i>d</i> macro is and returns
it.&nbsp; This detection process is somewhat involved, so I won't go into <i>how</i>
it works here, but suffice to say it <i>does</i> work.
</div>
<div>
Using automatic recursion to reenter various sets of macros is obviously much simpler.&nbsp;
It completely hides the underlying implementation details.&nbsp;
So, if it is so much easier to use, why do the state parameters still exist?&nbsp;
The reason is simple as well.&nbsp;
When state parameters are used, the state is <i>known</i> at all times.&nbsp;
This is not the case when automatic recursion is used.&nbsp;
The automatic recursion mechanism has to <i>deduce</i> the state at each point that it is used.&nbsp;
This implies a cost in macro complexity that in some situations--notably at deep macro depths--will slow
Using automatic recursion to reenter various seqs of macros is obviously much
simpler.&nbsp; It completely hides the underlying implementation details.&nbsp;
So, if it is so much easier to use, why do the state parameters still
exist?&nbsp; The reason is simple as well.&nbsp; When state parameters are
used, the state is <i>known</i> at all times.&nbsp; This is not the case when
automatic recursion is used.&nbsp; The automatic recursion mechanism has to <i>deduce</i>
the state at each point that it is used.&nbsp; This implies a cost in macro
complexity that in some situations--notably at deep macro depths--will slow
some preprocessors to a crawl.
</div>
<h4>Conclusion</h4>
<h4>
Conclusion
</h4>
<div>
It is really a tradeoff whether to use state parameters or automatic recursion for reentrancy.&nbsp;
The strengths of automatic recursion are ease of use and implementation encapsulation.&nbsp;
These come at a performance cost on some preprocessors in some situations.&nbsp;
The primary strength of state parameters, on the other hand, is efficiency.&nbsp;
Use of the state parameters is the only way to achieve <i>maximum</i> efficiency.&nbsp;
This efficiency comes at the cost of both code complexity and exposition of implementation.
It is really a tradeoff whether to use state parameters or automatic recursion
for reentrancy.&nbsp; The strengths of automatic recursion are ease of use and
implementation encapsulation.&nbsp; These come at a performance cost on some
preprocessors in some situations.&nbsp; The primary strength of state
parameters, on the other hand, is efficiency.&nbsp; Use of the state parameters
is the only way to achieve <i>maximum</i> efficiency.&nbsp; This efficiency
comes at the cost of both code complexity and exposition of implementation.
</div>
<h4>See Also</h4>
<h4>
See Also
</h4>
<ul>
<li><a href="../ref/for.html">BOOST_PP_FOR</a></li>
<li><a href="../ref/repeat.html">BOOST_PP_REPEAT</a></li>
<li><a href="../ref/while.html">BOOST_PP_WHILE</a></li>
<li>
<a href="../ref/for.html">BOOST_PP_FOR</a></li>
<li>
<a href="../ref/repeat.html">BOOST_PP_REPEAT</a></li>
<li>
<a href="../ref/while.html">BOOST_PP_WHILE</a></li>
</ul>
<div class="sig">- Paul Mensonides</div>
<div class="sig">
- Paul Mensonides
</div>
</body>
</html>