1 # /* Copyright (C) 2002
2 #  * Housemarque Oy
3 #  * http://www.housemarque.com
4 #  *
5 #  * Distributed under the Boost Software License, Version 1.0. (See
6 #  * accompanying file LICENSE_1_0.txt or copy at
7 #  * http://www.boost.org/LICENSE_1_0.txt)
8 #  */
9 #
10 # /* Revised by Paul Mensonides (2002) */
11 #
12 # /* See http://www.boost.org for most recent version. */
13 #
14 # /* This example shows how BOOST_PP_WHILE() can be used for implementing macros. */
15 #
16 # include <stdio.h>
17 #
18 # include <boost/preprocessor/arithmetic/add.hpp>
19 # include <boost/preprocessor/arithmetic/sub.hpp>
20 # include <boost/preprocessor/comparison/less_equal.hpp>
21 # include <boost/preprocessor/control/while.hpp>
22 # include <boost/preprocessor/list/adt.hpp>
23 # include <boost/preprocessor/tuple/elem.hpp>
24 #
25 # /* First consider the following C implementation of Fibonacci. */
26 
27 typedef struct linear_fib_state {
28    int a0, a1, n;
29 } linear_fib_state;
30 
linear_fib_c(linear_fib_state p)31 static int linear_fib_c(linear_fib_state p) {
32    return p.n;
33 }
34 
linear_fib_f(linear_fib_state p)35 static linear_fib_state linear_fib_f(linear_fib_state p) {
36    linear_fib_state r = { p.a1, p.a0 + p.a1, p.n - 1 };
37    return r;
38 }
39 
linear_fib(int n)40 static int linear_fib(int n) {
41    linear_fib_state p = { 0, 1, n };
42    while (linear_fib_c(p)) {
43       p = linear_fib_f(p);
44    }
45    return p.a0;
46 }
47 
48 # /* Then consider the following preprocessor implementation of Fibonacci. */
49 #
50 # define LINEAR_FIB(n) LINEAR_FIB_D(1, n)
51 # /* Since the macro is implemented using BOOST_PP_WHILE, the actual
52 #  * implementation takes a depth as a parameters so that it can be called
53 #  * inside a BOOST_PP_WHILE.  The above easy-to-use version simply uses 1
54 #  * as the depth and cannot be called inside a BOOST_PP_WHILE.
55 #  */
56 #
57 # define LINEAR_FIB_D(d, n) \
58    BOOST_PP_TUPLE_ELEM(3, 0, BOOST_PP_WHILE_ ## d(LINEAR_FIB_C, LINEAR_FIB_F, (0, 1, n)))
59 # /*                   ^^^^                 ^^^^^           ^^            ^^   ^^^^^^^
60 #  *                    #1                   #2             #3            #3     #4
61 #  *
62 #  * 1) The state is a 3-element tuple.  After the iteration is finished, the first
63 #  *    element of the tuple is the result.
64 #  *
65 #  * 2) The WHILE primitive is "invoked" directly.  BOOST_PP_WHILE(D, ...)
66 #  *    can't be used because it would not be expanded by the preprocessor.
67 #  *
68 #  * 3) ???_C is the condition and ???_F is the iteration macro.
69 #  */
70 #
71 # define LINEAR_FIB_C(d, p) \
72    /* p.n */ BOOST_PP_TUPLE_ELEM(3, 2, p) \
73    /**/
74 #
75 # define LINEAR_FIB_F(d, p) \
76    ( \
77       /* p.a1 */ BOOST_PP_TUPLE_ELEM(3, 1, p), \
78       /* p.a0 + p.a1 */ BOOST_PP_ADD_D(d, BOOST_PP_TUPLE_ELEM(3, 0, p), BOOST_PP_TUPLE_ELEM(3, 1, p)), \
79                         /*          ^^ ^ \
80                          * BOOST_PP_ADD() uses BOOST_PP_WHILE().  Therefore we \
81                          * pass the recursion depth explicitly to BOOST_PP_ADD_D(). \
82                          */ \
83       /* p.n - 1 */ BOOST_PP_DEC(BOOST_PP_TUPLE_ELEM(3, 2, p)) \
84    ) \
85    /**/
86 
main()87 int main() {
88    printf("linear_fib(10) = %d\n", linear_fib(10));
89    printf("LINEAR_FIB(10) = %d\n", LINEAR_FIB(10));
90    return 0;
91 }
92