Boost logo

Boost :

From: Vesa Karvonen (vesa.karvonen_at_[hidden])
Date: 2001-12-17 15:27:15


/* This message can be preprocessed! :) */

#include <boost/preprocessor.hpp>

/*
  I recently discovered a technique for representing "general
  purpose" recursive data structures such as lists and trees using
  the preprocessor.

  Consider the following list constructor macros:
*/

#define BOOST_PREPROCESSOR_LIST_NIL\
  (_,_,0)
#define BOOST_PREPROCESSOR_LIST_CONS(H,T)\
  (H,T,1)

/*
  The simple trick is that the last element of the tuple indicates
  whether the node is a NIL node or a CONS node. This kind of
  representation makes it possible to define algorithms for lists
  without having to know what kind of elements are stored in the
  list.
*/

/* A simple list would look like this: */

#define TEST_LIST\
  BOOST_PREPROCESSOR_LIST_CONS(1,\
  BOOST_PREPROCESSOR_LIST_CONS(2,\
  BOOST_PREPROCESSOR_LIST_CONS(3,\
  BOOST_PREPROCESSOR_LIST_CONS(4,\
  BOOST_PREPROCESSOR_LIST_CONS(5,\
  BOOST_PREPROCESSOR_LIST_NIL)))))

list: TEST_LIST

/* The following are the other elementary operations on lists: */

#define BOOST_PREPROCESSOR_LIST_IS_CONS(L)\
  BOOST_PREPROCESSOR_TUPLE_ELEM(3,2,L)
#define BOOST_PREPROCESSOR_LIST_IS_NIL(L)\
  BOOST_PREPROCESSOR_NOT(BOOST_PREPROCESSOR_TUPLE_ELEM(3,2,L))
#define BOOST_PREPROCESSOR_LIST_HEAD(L)\
  BOOST_PREPROCESSOR_TUPLE_ELEM(3,0,L)
#define BOOST_PREPROCESSOR_LIST_TAIL(L)\
  BOOST_PREPROCESSOR_TUPLE_ELEM(3,1,L)

/* The following macros can be used to compute the length of a list: */

#define BOOST_PREPROCESSOR_LIST_SIZE(L)\
  BOOST_PREPROCESSOR_LIST_SIZE_I(0,L)
#define BOOST_PREPROCESSOR_LIST_SIZE_I(I,L)\
  BOOST_PREPROCESSOR_TUPLE_ELEM\
  ( 2\
  , 0\
  , BOOST_PREPROCESSOR_WHILE##I\
    ( BOOST_PREPROCESSOR_LIST_SIZE_C\
    , BOOST_PREPROCESSOR_LIST_SIZE_F\
    , (0,L)\
    )\
  )
#define BOOST_PREPROCESSOR_LIST_SIZE_C(I,X)\
  BOOST_PREPROCESSOR_LIST_IS_CONS(BOOST_PREPROCESSOR_TUPLE_ELEM(2,1,X))
#define BOOST_PREPROCESSOR_LIST_SIZE_F(I,X)\
  ( BOOST_PREPROCESSOR_INC(BOOST_PREPROCESSOR_TUPLE_ELEM(2,0,X))\
  , BOOST_PREPROCESSOR_LIST_TAIL(BOOST_PREPROCESSOR_TUPLE_ELEM(2,1,X))\
  )

/* For example: */

size: BOOST_PREPROCESSOR_LIST_SIZE(TEST_LIST)

/* The following implements a well known higher order function: */

#define BOOST_PREPROCESSOR_LIST_FOLD_LEFT_I(I,F,R,L)\
  BOOST_PREPROCESSOR_TUPLE_ELEM\
  ( 3\
  , 1\
  , BOOST_PREPROCESSOR_WHILE##I\
    ( BOOST_PREPROCESSOR_LIST_FOLD_LEFT_C\
    , BOOST_PREPROCESSOR_LIST_FOLD_LEFT_F\
    , (F,R,L)\
    )\
  )
#define BOOST_PREPROCESSOR_LIST_FOLD_LEFT_C(I,X)\
  BOOST_PREPROCESSOR_LIST_IS_CONS(BOOST_PREPROCESSOR_TUPLE_ELEM(3,2,X))
#define BOOST_PREPROCESSOR_LIST_FOLD_LEFT_F(I,X)\
  ( BOOST_PREPROCESSOR_TUPLE_ELEM(3,0,X)\
  , BOOST_PREPROCESSOR_TUPLE_ELEM(3,0,X)\
    ( BOOST_PREPROCESSOR_INC(I)\
    , BOOST_PREPROCESSOR_TUPLE_ELEM(3,1,X)\
    , BOOST_PREPROCESSOR_LIST_HEAD(BOOST_PREPROCESSOR_TUPLE_ELEM(3,2,X)))\
    , BOOST_PREPROCESSOR_LIST_TAIL(BOOST_PREPROCESSOR_TUPLE_ELEM(3,2,X))\
  )

/* And here is an example of how to use it: */

fold:
BOOST_PREPROCESSOR_LIST_FOLD_LEFT_I(0,BOOST_PREPROCESSOR_SUB_I,20,TEST_LIST)

/*
  The following is list reversal implemented using the previously
  defined higher order function:
*/

#define BOOST_PREPROCESSOR_LIST_REV_I(I,L)\
  BOOST_PREPROCESSOR_LIST_FOLD_LEFT_I\
  ( I\
  , BOOST_PREPROCESSOR_LIST_REV_F\
  , BOOST_PREPROCESSOR_LIST_NIL\
  , L\
  )
#define BOOST_PREPROCESSOR_LIST_REV_F(I,R,H)\
  BOOST_PREPROCESSOR_LIST_CONS(H,R)

/* For example: */

rev: BOOST_PREPROCESSOR_LIST_REV_I(0,TEST_LIST)

/* Finally, here is another well known higher order function: */

#define BOOST_PREPROCESSOR_LIST_MAP_I(I,F,S,L)\
  BOOST_PREPROCESSOR_LIST_REV_I\
  ( I\
  , BOOST_PREPROCESSOR_TUPLE_ELEM\
    ( 3\
    , 2\
    , BOOST_PREPROCESSOR_LIST_FOLD_LEFT_I\
      ( I\
      , BOOST_PREPROCESSOR_LIST_MAP_F\
      , (F,S,BOOST_PREPROCESSOR_LIST_NIL)\
      , L\
      )\
    )\
  )
#define BOOST_PREPROCESSOR_LIST_MAP_F(I,R,H)\
  ( BOOST_PREPROCESSOR_TUPLE_ELEM(3,0,R)\
  , BOOST_PREPROCESSOR_TUPLE_ELEM(3,1,R)\
  , BOOST_PREPROCESSOR_LIST_CONS\
    ( BOOST_PREPROCESSOR_TUPLE_ELEM(3,0,R)\
      ( I\
      , BOOST_PREPROCESSOR_TUPLE_ELEM(3,1,R)\
      , H\
      )\
    , BOOST_PREPROCESSOR_TUPLE_ELEM(3,2,R))\
  )

/* And an example: */

#define BOOST_PREPROCESSOR_INC_I(I,_,X) BOOST_PREPROCESSOR_INC(X)
map: BOOST_PREPROCESSOR_LIST_MAP_I(0,BOOST_PREPROCESSOR_INC_I,_,TEST_LIST)

/*
  The question is: Should this functionality be added to
  the preprocessor library?

  Personally, I have no idea of how useful this stuff would be.
  I'd like to know if anyone has ideas on how to use the
  functionality or is otherwise interested.
*/


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk