linear_fib.c 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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. typedef struct linear_fib_state {
  27. int a0, a1, n;
  28. } linear_fib_state;
  29. static int linear_fib_c(linear_fib_state p) {
  30. return p.n;
  31. }
  32. static linear_fib_state linear_fib_f(linear_fib_state p) {
  33. linear_fib_state r = { p.a1, p.a0 + p.a1, p.n - 1 };
  34. return r;
  35. }
  36. static int linear_fib(int n) {
  37. linear_fib_state p = { 0, 1, n };
  38. while (linear_fib_c(p)) {
  39. p = linear_fib_f(p);
  40. }
  41. return p.a0;
  42. }
  43. # /* Then consider the following preprocessor implementation of Fibonacci. */
  44. #
  45. # define LINEAR_FIB(n) LINEAR_FIB_D(1, n)
  46. # /* Since the macro is implemented using BOOST_PP_WHILE, the actual
  47. # * implementation takes a depth as a parameters so that it can be called
  48. # * inside a BOOST_PP_WHILE. The above easy-to-use version simply uses 1
  49. # * as the depth and cannot be called inside a BOOST_PP_WHILE.
  50. # */
  51. #
  52. # define LINEAR_FIB_D(d, n) \
  53. BOOST_PP_TUPLE_ELEM(3, 0, BOOST_PP_WHILE_ ## d(LINEAR_FIB_C, LINEAR_FIB_F, (0, 1, n)))
  54. # /* ^^^^ ^^^^^ ^^ ^^ ^^^^^^^
  55. # * #1 #2 #3 #3 #4
  56. # *
  57. # * 1) The state is a 3-element tuple. After the iteration is finished, the first
  58. # * element of the tuple is the result.
  59. # *
  60. # * 2) The WHILE primitive is "invoked" directly. BOOST_PP_WHILE(D, ...)
  61. # * can't be used because it would not be expanded by the preprocessor.
  62. # *
  63. # * 3) ???_C is the condition and ???_F is the iteration macro.
  64. # */
  65. #
  66. # define LINEAR_FIB_C(d, p) \
  67. /* p.n */ BOOST_PP_TUPLE_ELEM(3, 2, p) \
  68. /**/
  69. #
  70. # define LINEAR_FIB_F(d, p) \
  71. ( \
  72. /* p.a1 */ BOOST_PP_TUPLE_ELEM(3, 1, p), \
  73. /* p.a0 + p.a1 */ BOOST_PP_ADD_D(d, BOOST_PP_TUPLE_ELEM(3, 0, p), BOOST_PP_TUPLE_ELEM(3, 1, p)), \
  74. /* ^^ ^ \
  75. * BOOST_PP_ADD() uses BOOST_PP_WHILE(). Therefore we \
  76. * pass the recursion depth explicitly to BOOST_PP_ADD_D(). \
  77. */ \
  78. /* p.n - 1 */ BOOST_PP_DEC(BOOST_PP_TUPLE_ELEM(3, 2, p)) \
  79. ) \
  80. /**/
  81. int main() {
  82. printf("linear_fib(10) = %d\n", linear_fib(10));
  83. printf("LINEAR_FIB(10) = %d\n", LINEAR_FIB(10));
  84. return 0;
  85. }