Brian Silverman | f27e085 | 2018-08-04 23:56:45 -0700 | [diff] [blame^] | 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 | |
| 31 | static int linear_fib_c(linear_fib_state p) { |
| 32 | return p.n; |
| 33 | } |
| 34 | |
| 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 | |
| 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 | |
| 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 | } |