// Copyright David Abrahams 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_FORWARD_DWA2006324_HPP
# define BOOST_FORWARD_DWA2006324_HPP

# include <boost/preprocessor/seq/seq.hpp>
# include <boost/preprocessor/seq/elem.hpp>
# include <boost/preprocessor/seq/for_each_product.hpp>
# include <boost/preprocessor/seq/for_each_i.hpp>
# include <boost/preprocessor/control/while.hpp>
# include <boost/preprocessor/control/expr_iif.hpp>
# include <boost/preprocessor/comparison/not_equal.hpp>
# include <boost/preprocessor/punctuation/comma_if.hpp>

// Generates a Boost.Preprocessor Sequence representing all the binary
// numbers from 0 to 2^n-1.  Each element of the result is an
// n-element Sequence whose elements are 1s and 0s. For example,
//
//   BOOST_FORWARD_BINARY_SEQ(2)
//
// generates
//
//   ((0)(0)) ((0)(1)) ((1)(0)) ((1)(1))
//
# define BOOST_FORWARD_BINARY_SEQ(n)            \
    BOOST_PP_SEQ_ELEM(                          \
        1                                       \
      , BOOST_PP_WHILE(                         \
          BOOST_FORWARD_SEQ_HEAD_NONZERO        \
        , BOOST_FORWARD_COUNT_BINARY            \
        , (n)( (BOOST_PP_SEQ_NIL) )             \
      )                                         \
    )

// More efficient version of the same macro that can be used when the
// re-entrancy depth is known.
# define BOOST_FORWARD_BINARY_SEQ_D(d,n)        \
    BOOST_PP_SEQ_ELEM(                          \
        1                                       \
      , BOOST_PP_WHILE_##d(                     \
          BOOST_FORWARD_SEQ_HEAD_NONZERO        \
        , BOOST_FORWARD_COUNT_BINARY            \
        , (n)( (BOOST_PP_SEQ_NIL) )             \
      )                                         \
    )

// A predicate for use with BOOST_PP_WHILE that is true iff the head
// of seq is nonzero
# define BOOST_FORWARD_SEQ_HEAD_NONZERO(r, seq) \
    BOOST_PP_SEQ_ELEM(0, seq)

// Update state for BOOST_FORWARD_BINARY_SEQ(_D).
//
// Requires: state is a Sequence of the form (n)( binary ) where n is
// a remaining number of iterations and binary is a Sequence whose
// elements BOOST_PP_SEQ_NIL or are themselves Sequences of 1s and 0s.
//
// Generates: a new Sequence of the form (n)( binary01 ) where
// binary01 is a sequence consisting of the cross-product of binary
// with (0)(1).
# define BOOST_FORWARD_COUNT_BINARY(r, state)       \
    (BOOST_PP_DEC(BOOST_PP_SEQ_HEAD(state)))        \
        (BOOST_PP_SEQ_FOR_EACH_PRODUCT_R(           \
             r                                      \
           , BOOST_FORWARD_COMPOSE_BINARY           \
           , BOOST_PP_SEQ_TAIL(state)((0)(1))  ) )

# define BOOST_FORWARD_COMPOSE_BINARY(r, elements) \
    (BOOST_PP_SEQ_ELEM(0,elements)(BOOST_PP_SEQ_ELEM(1,elements)))

# define BOOST_FORWARD_BINARY_PARAM(r, names, i, elem)   \
    BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0,names),i) BOOST_PP_EXPR_IIF(elem,const) & BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names),i)

# define BOOST_FORWARD_ENUM_BINARY_PARAM_SEQ(constness_seq, type_name, param_name)   \
    BOOST_PP_SEQ_FOR_EACH_I(BOOST_FORWARD_BINARY_PARAM,(type_name)(param_name), constness_seq)

# define BOOST_FORWARD_ENUM_BINARY_PARAM_SEQ_R(r, constness_seq, type_name, param_name)              \
    BOOST_PP_SEQ_FOR_EACH_I_R(r, BOOST_FORWARD_BINARY_PARAM,(type_name)(param_name), constness_seq)


#endif

