Boost C++ Libraries: Ticket #4455: clean up preprocessor/seq/fold_left.hpp https://svn.boost.org/trac10/ticket/4455 <p> introductionary notes: </p> <p> BOOST_PP_SEQ_FOLD_LEFT is a macro that applies a submitted macro (henceforth called operation) to all elements of a sequence, starting with element 0 (leftmost). The operation macro op(n, state, elem) takes three arguments, the first being a counter starting from 2 and incremented after each operation, second, an arbitrary sequence of preprocessing tokens comprising the intermediate result (or current state), and finally the current element, stripped of the embracing parentheses. The result of the operation is an updated state, passed on to the next call to the operation. </p> <p> BOOST_PP_SEQ_FOLD_LEFT is called with three parameters: first, the name of the operation macro, second, the initial state, and third, the sequence to which to apply the operation element-wise. It returnes the final state. </p> <p> Since the above mentioned counter starts from 2, submitting a sequence of length 256 to BOOST_SEQ_FOLD_LEFT will result in a final call to the operation macro with its first parameter set to 257. I neither expect a counter starting from anything but 0 or 1, nor do I expect, it might get me out of the arithmetic range, so I consider this a really bad design decision. </p> <p> The 1.43 implementation of BOOST_PP_SEQ_FOLD_LEFT contains a huge amount of what seems to be leftovers from a major rework, not having been removed yet, and, in addition, allows for significant reduction of evaluation costs. </p> <p> fold_left.hpp is now simplified in 3 major steps. </p> <p> step 1: </p> <p> The definition of BOOST_PP_SEQ_FOLD_LEFT entails a call to BOOST_PP_AUTO_REC. In short, this call turns out to be completely pointless, as it will always return 1 as result, and can be simply replaced by this constant. </p> <p> This can be seen as follows: </p> <p> BOOST_PP_AUTO_REC operates on macros P(n), that </p> <ul><li>take integers from 1 to 256 as paramater; </li><li>are binary, i.e. yields only 0 or 1 as a result; </li><li>are monotonely rising, i.e. there is an integer n such that P(i) == 0 for i &lt; n and == 1 otherwise. </li></ul><p> BOOST_PP_AUTO_SEC is designed to find the 'leap position' where P assumes 1 for the first time. </p> <p> BOOST_PP_SEQ_FOLD_LEFT_P is such a P(n). Although the replacement of BOOST_PP_SEQ_FOLD_LEFT_P looks complex, a closer look at </p> <pre class="wiki">BOOST_PP_SEQ_FOLD_LEFT_I_ ## n(BOOST_PP_SEQ_FOLD_LEFT_O, BOOST_PP_NIL, (nil), 1) </pre><p> reveals, that this expression, independently of n, will always expand to BOOST_PP_NIL, and after some more replacing, BOOST_PP_SEQ_FOLD_LEFT_P turns out to be constantly 1. Consequently, BOOST_PP_AUTO_REC, applied to this (constant) macro, will yield 1 as a result. </p> <p> Hence simplify the definition of BOOST_PP_SEQ_FOLD_LEFT: </p> <pre class="wiki"># define BOOST_PP_SEQ_FOLD_LEFT BOOST_PP_SEQ_FOLD_LEFT_1 </pre><p> step 2: </p> <p> Now, that BOOST_PP_SEQ_FOLD_LEFT_P has been eliminated, its definition may be removed. Then, none of the BOOST_PP_SEQ_FOLD_LEFT_CHECK_* macros are called any more (not only in fold_left.hpp, but throughout the whole preprocessor branch). The same holds for some other macros as well. Here is the list: </p> <ul><li>BOOST_PP_SEQ_FOLD_LEFT_P; </li><li>BOOST_PP_SEQ_FOLD_LEFT_O; </li><li>BOOST_PP_SEQ_FOLD_LEFT_CHECK_*; </li><li>BOOST_PP_SEQ_FOLD_LEFT_*257; </li><li>BOOST_PP_SEQ_FOLD_LEFT_n for 2 &lt;= n &lt;= 256; </li></ul><p> Drop their definitions. </p> <p> step 3 </p> <p> The loop iterating over the elements has been unrolled disadvantageously. Although the length of the sequence is determined in advance, the loop starts in a forward manner and, thus, has to permanently check when to terminate. A countdown strategy is more appropriate here, automatically terminating when iteration 1 is reached. This saves a couple of macro replacements per iteration. Because of the 257 quirk of BOOST_PP_SEQ_FOLD_LEFT mentioned in the first section, an extra parameter q257 has to be introduced, controlling the setting of the counter to the somewhat irregular value 257 when a sequence of length 256 is encountered. </p> <p> While the reduction and dropping in step 1 and 2 should not be affected by preprocessor quirks, the optimization carried out here might be susceptible to them. So, for safety reasons, this optimization takes effect only when BOOST_PP_CONFIG_FLAGS() is equal to BOOST_PP_CONFIG_STRICT(). </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/4455 Trac 1.4.3 anonymous Tue, 20 Jul 2010 15:06:28 GMT attachment set https://svn.boost.org/trac10/ticket/4455 https://svn.boost.org/trac10/ticket/4455 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">seq_fold_left.patch</span> </li> </ul> Ticket ookami1@… Tue, 20 Jul 2010 15:08:23 GMT severity changed https://svn.boost.org/trac10/ticket/4455#comment:1 https://svn.boost.org/trac10/ticket/4455#comment:1 <ul> <li><strong>severity</strong> <span class="trac-field-old">Problem</span> → <span class="trac-field-new">Optimization</span> </li> </ul> Ticket ookami1@… Tue, 20 Jul 2010 15:11:03 GMT <link>https://svn.boost.org/trac10/ticket/4455#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4455#comment:2</guid> <description> <p> Forgot to add my name and a greeting: </p> <p> Cheers Wolf Lammen </p> </description> <category>Ticket</category> </item> <item> <author>ookami1@…</author> <pubDate>Tue, 20 Jul 2010 15:18:44 GMT</pubDate> <title>type, component changed; owner set https://svn.boost.org/trac10/ticket/4455#comment:3 https://svn.boost.org/trac10/ticket/4455#comment:3 <ul> <li><strong>owner</strong> set to <span class="trac-author">No-Maintainer</span> </li> <li><strong>type</strong> <span class="trac-field-old">Bugs</span> → <span class="trac-field-new">Library Submissions</span> </li> <li><strong>component</strong> <span class="trac-field-old">None</span> → <span class="trac-field-new">preprocessor</span> </li> </ul> Ticket ookami1@… Tue, 20 Jul 2010 15:40:40 GMT attachment set https://svn.boost.org/trac10/ticket/4455 https://svn.boost.org/trac10/ticket/4455 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">seq_fold_left.2.patch</span> </li> </ul> <p> takes BOOST_PP_SEQ_FOLD_RIGHT into account </p> Ticket ookami1@… Tue, 20 Jul 2010 15:42:05 GMT <link>https://svn.boost.org/trac10/ticket/4455#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4455#comment:4</guid> <description> <p> Forget step 3 for the time being, as this would break BOOST_PP_SEQ_FOLD_RIGHT </p> <p> Cheers </p> <p> Wolf Lammen </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Steven Watanabe</dc:creator> <pubDate>Tue, 20 Jul 2010 16:05:41 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4455#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4455#comment:5</guid> <description> <p> Replying to <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/4455" title="#4455: Library Submissions: clean up preprocessor/seq/fold_left.hpp (closed: invalid)">anonymous</a>: </p> <blockquote class="citation"> <p> step 1: </p> <p> The definition of BOOST_PP_SEQ_FOLD_LEFT entails a call to BOOST_PP_AUTO_REC. In short, this call turns out to be completely pointless, as it will always return 1 as result, and can be simply replaced by this constant. </p> <p> This can be seen as follows: </p> <p> BOOST_PP_AUTO_REC operates on macros P(n), that </p> <ul><li>take integers from 1 to 256 as paramater; </li><li>are binary, i.e. yields only 0 or 1 as a result; </li><li>are monotonely rising, i.e. there is an integer n such that P(i) == 0 for i &lt; n and == 1 otherwise. </li></ul><p> BOOST_PP_AUTO_SEC is designed to find the 'leap position' where P assumes 1 for the first time. </p> <p> BOOST_PP_SEQ_FOLD_LEFT_P is such a P(n). Although the replacement of BOOST_PP_SEQ_FOLD_LEFT_P looks complex, a closer look at </p> <pre class="wiki">BOOST_PP_SEQ_FOLD_LEFT_I_ ## n(BOOST_PP_SEQ_FOLD_LEFT_O, BOOST_PP_NIL, (nil), 1) </pre><p> reveals, that this expression, independently of n, will always expand to BOOST_PP_NIL, and after some more replacing, BOOST_PP_SEQ_FOLD_LEFT_P turns out to be constantly 1. Consequently, BOOST_PP_AUTO_REC, applied to this (constant) macro, will yield 1 as a result. </p> </blockquote> <p> Nope. BOOST_PP_SEQ_FOLD_LEFT_P expands to 1 iff. <strong>we are not currently in an expansion of BOOST_PP_SEQ_FOLD_LEFT_I_ ## n</strong>. If BOOST_PP_SEQ_FOLD_LEFT_I_ ## n is being expanded, then it will not be expanded again, since recursive calls to a macro are not expanded. BOOST_PP_AUTO_REC is used to find the first available index that is not on the macro expansion stack. This allows nested calls to BOOST_PP_SEQ_FOLD_LEFT. Note that the s parameter to the macro is not the index in the sequence. It is the next available index for reentering BOOST_PP_FOLD_LEFT. See <a href="http://www.boost.org/libs/preprocessor/doc/ref/seq_fold_left.html">http://www.boost.org/libs/preprocessor/doc/ref/seq_fold_left.html</a>. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Wed, 21 Jul 2010 18:02:30 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/4455#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/4455#comment:6</guid> <description> <p> Yes, judging from how BOOST_PP_SEQ_FOLD_LEFT_* macros were used, I already had the idea, they might be a pool of macros shared among several loops. I just did not see how this pool was managed, so I thought 'get rid of it!'. </p> <p> Your explanation fills in here, and I mark this ticket as invalid (that is if I have sufficient right to do so). </p> <p> Cheers </p> <p> Wolf Lammen </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Wed, 21 Jul 2010 18:07:53 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/4455#comment:7 https://svn.boost.org/trac10/ticket/4455#comment:7 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">invalid</span> </li> </ul> Ticket