// bsls_macrorepeat.h                                                 -*-C++-*-
#ifndef INCLUDED_BSLS_MACROREPEAT
#define INCLUDED_BSLS_MACROREPEAT

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: repeat a macro invocation with different numeric arguments.
//
//@CLASSES:
//
//@MACROS:
// BSLS_MACROREPEAT(N, MACRO): Invoke 'MACRO(1) MACRO(2) ... MACRO(N)'
// BSLS_MACROREPEAT_COMMA(N, MACRO): 'N' comma-separated invocations of 'MACRO'
// BSLS_MACROREPEAT_SEP(N, MACRO, S): 'N' invocations of 'MACRO' separated by S
//
//@SEE_ALSO:
//
//@DESCRIPTION: This component provides a set of macros that expand to multiple
// repetitions of a user-specified "repetition phrase".  The repetition phrase
// is specified as macro that is invoked multiple times in each invocation of a
// 'BSLS_MACROREPEAT*' macro.  For example:
//..
//  #define FOO(n) foo ## n
//  doit(BSLS_MACROREPEAT_COMMA(5, FOO));
//..
// will expand FOO(n) with arguments 1 through 5, inserting commas between the
// expansions, resulting in:
//..
//  doit(foo1, foo2, foo3, foo4, foo5);
//..
// Use of these macros is less error-prone and often more compact than manually
// repeating the specified pattern.  In addition, it is sometimes more readable
// than the cut-and-paste alternative because the reader does not need to
// examine each argument to verify that it forms a linear sequence.
//
// Each of these macros can appear within the repetition phrase of another of
// these macros but, because of limitations in the C proprocessor language,
// none of these macros can appear (directly or indirectly) within its own
// repetition phrase.
//
///Usage
///-----
// The following examples demonstrate potential uses of the macros in this
// component.
//
///Example 1: Repeated Template Instantiation
/// - - - - - - - - - - - - - - - - - - - - -
// In this example, we wish to explicitly instantiate a template with a
// sequence of integer values.  First, assume a function template 'foo<V>' that
// adds the (compile-time) value 'V' to a global 'total' each time it is
// called:
//..
//  int total = 0;
//  template <int V> void foo() { total += V; }
//..
// Now, if we instantiate and call 'foo<X>()' once for each 'X' in the range
// '2' to '6'.  To do that, we create a macro, 'FOO_STMNT(X)' which and calls
// 'foo<X+1>' (i.e., 'FOO_STMNT(1)' will call 'foo<2>()').  Then we invoke
// 'FOO_STMNT' 5 times with arguments 1, 2, 3, 4, and 5 using the
// 'BSLS_MACROREPEAT' macro:
//..
//  int main() {
//
//      #define FOO_STMNT(X) foo<X+1>();  // Semicolon at end of each statement
//      BSLS_MACROREPEAT(5, FOO_STMNT)
//      assert(20 == total);
//      return 0;
// }
//..
//
///Example 2: Repeated Function Arguments
/// - - - - - - - - - - - - - - - - - - -
// In this example, we supply as series of identical arguments to a function
// invocation, using 'BSLS_MACROREPEAT_COMMA'.  First, assume a function,
// 'fmtQuartet' that takes four integer arguments and formats them into a
// string:
//..
//  #include <cstring>
//  #include <cstdio>
//
//  void fmtQuartet(char *result, int a, int b, int c, int d) {
//      std::sprintf(result, "%d %d %d %d", a, b, c, d);
//  }
//..
// Now we wish to invoke this function, but in a context where the last three
// arguments are always the same as each other.  For this situation we define a
// macro 'X(x)' that ignores its argument and simply expands to an unchanging
// set of tokens.  If the repeated argument is named 'i', then the expansion of
// 'X(x)' is simply '(i)':
//..
//  int main() {
//      char buffer[20];
//      int i = 8;
//      #define X(x) (i)
//..
// Finally, we invoke macro 'X(x)' three times within the argument list of
// 'fmtQuart'.  We use 'BSLS_MACROREPEAT_COMMA' for these invocations, as it
// inserts a comma between each repetition:
//..
//      fmtQuartet(buffer, "%d %d %d %d", 7, BSLS_MACROREPEAT_COMMA(3, X));
//      assert(0 == std::strcmp(buffer, "7 8 8 8"));
//      return 0;
//  }
//..
//
///Example 3: Bitmask Computation
/// - - - - - - - - - - - - - - -
// In this example, we Compute (at compile time) a 7-bit mask.  First, we
// defined a macro 'BITVAL' that computes the value of a single bit 'B' in the
// mask:
//..
//  #define BITVAL(B) (1 << (B - 1))
//..
// Then we use the 'BSLS_MACROREPEAT_SEP' to invoke 'BITVAL' 7 times,
// separating the repetitions with the bitwise OR operator:
//..
//  const unsigned mask = BSLS_MACROREPEAT_SEP(7, BITVAL, |);
//
//  int main() {
//      assert(127 == mask);
//      return 0;
//  }
//..

#define BSLS_MACROREPEAT(N, MACRO) BSLS_MACROREPEAT_##N(MACRO)
    // Expand to 'N' invocations of 'MACRO(x)', where 'x' in each invocation is
    // the next number in the sequence from '1' to 'N'.  If 'N' is '0', then
    // the expansion is empty.  For example 'BSLS_MACROREPEAT(3, XYZ)' expands
    // to 'XYZ(1) XYZ(2) XYZ(3)'.  The behavior is undefined unless 'N' is a
    // decimal integer (or is a macro that expands to a decimal integer) in the
    // range 0 to 20.  Note that 'MACRO' is typically a macro with one
    // argument, but may also be a function or functor.

#define BSLS_MACROREPEAT_COMMA(N, MACRO) BSLS_MACROREPEAT_C##N(MACRO)
    // Expand to 'N' comma-separated invocations of 'MACRO(x)', where 'x' in
    // each invocation is the next number in the sequence from '1' to 'N'.  If
    // 'N' is '0', then the expansion is empty.  For example
    // 'BSLS_MACROREPEAT_COMMA(3, XYZ)' expands to 'XYZ(1), XYZ(2), XYZ(3)'.
    // The behavior is undefined unless 'N' is a decimal integer (or is a macro
    // that expands to a decimal integer) in the range 0 to 20.  Note that
    // 'MACRO' is typically a macro with one argument, but may also be a
    // function or functor.

#define BSLS_MACROREPEAT_SEP(N, MACRO, S) BSLS_MACROREPEAT_S##N(MACRO, S)
    // Expand to 'N' invocations of 'MACRO(x)' separated by the token sequence
    // 'S', where 'x' in each invocation is the next number in the sequence
    // from '1' to 'N'.  If 'N' is '0', then the expansion is empty.  For
    // example 'BSLS_MACROREPEAT_SEP(3, XYZ, ;)' expands to 'XYZ(1) ; XYZ(2) ;
    // XYZ(3)'.  The behavior is undefined unless 'N' is a decimal integer (or
    // is a macro that expands to a decimal integer) in the range 0 to 20.
    // Note that 'MACRO' is typically a macro with one argument, but may also
    // be a function or functor.

// ============================================================================
//                           IMPLEMENTATION MACROS
// ============================================================================

#define BSLS_MACROREPEAT_0(MACRO)
#define BSLS_MACROREPEAT_1(MACRO) MACRO(1)
#define BSLS_MACROREPEAT_2(MACRO) BSLS_MACROREPEAT_1(MACRO) MACRO(2)
#define BSLS_MACROREPEAT_3(MACRO) BSLS_MACROREPEAT_2(MACRO) MACRO(3)
#define BSLS_MACROREPEAT_4(MACRO) BSLS_MACROREPEAT_3(MACRO) MACRO(4)
#define BSLS_MACROREPEAT_5(MACRO) BSLS_MACROREPEAT_4(MACRO) MACRO(5)
#define BSLS_MACROREPEAT_6(MACRO) BSLS_MACROREPEAT_5(MACRO) MACRO(6)
#define BSLS_MACROREPEAT_7(MACRO) BSLS_MACROREPEAT_6(MACRO) MACRO(7)
#define BSLS_MACROREPEAT_8(MACRO) BSLS_MACROREPEAT_7(MACRO) MACRO(8)
#define BSLS_MACROREPEAT_9(MACRO) BSLS_MACROREPEAT_8(MACRO) MACRO(9)
#define BSLS_MACROREPEAT_10(MACRO) BSLS_MACROREPEAT_9(MACRO) MACRO(10)
#define BSLS_MACROREPEAT_11(MACRO) BSLS_MACROREPEAT_10(MACRO) MACRO(11)
#define BSLS_MACROREPEAT_12(MACRO) BSLS_MACROREPEAT_11(MACRO) MACRO(12)
#define BSLS_MACROREPEAT_13(MACRO) BSLS_MACROREPEAT_12(MACRO) MACRO(13)
#define BSLS_MACROREPEAT_14(MACRO) BSLS_MACROREPEAT_13(MACRO) MACRO(14)
#define BSLS_MACROREPEAT_15(MACRO) BSLS_MACROREPEAT_14(MACRO) MACRO(15)
#define BSLS_MACROREPEAT_16(MACRO) BSLS_MACROREPEAT_15(MACRO) MACRO(16)
#define BSLS_MACROREPEAT_17(MACRO) BSLS_MACROREPEAT_16(MACRO) MACRO(17)
#define BSLS_MACROREPEAT_18(MACRO) BSLS_MACROREPEAT_17(MACRO) MACRO(18)
#define BSLS_MACROREPEAT_19(MACRO) BSLS_MACROREPEAT_18(MACRO) MACRO(19)
#define BSLS_MACROREPEAT_20(MACRO) BSLS_MACROREPEAT_19(MACRO) MACRO(20)

#define BSLS_MACROREPEAT_C0(MACRO)
#define BSLS_MACROREPEAT_C1(MACRO) MACRO(1)
#define BSLS_MACROREPEAT_C2(MACRO) BSLS_MACROREPEAT_C1(MACRO), MACRO(2)
#define BSLS_MACROREPEAT_C3(MACRO) BSLS_MACROREPEAT_C2(MACRO), MACRO(3)
#define BSLS_MACROREPEAT_C4(MACRO) BSLS_MACROREPEAT_C3(MACRO), MACRO(4)
#define BSLS_MACROREPEAT_C5(MACRO) BSLS_MACROREPEAT_C4(MACRO), MACRO(5)
#define BSLS_MACROREPEAT_C6(MACRO) BSLS_MACROREPEAT_C5(MACRO), MACRO(6)
#define BSLS_MACROREPEAT_C7(MACRO) BSLS_MACROREPEAT_C6(MACRO), MACRO(7)
#define BSLS_MACROREPEAT_C8(MACRO) BSLS_MACROREPEAT_C7(MACRO), MACRO(8)
#define BSLS_MACROREPEAT_C9(MACRO) BSLS_MACROREPEAT_C8(MACRO), MACRO(9)
#define BSLS_MACROREPEAT_C10(MACRO) BSLS_MACROREPEAT_C9(MACRO), MACRO(10)
#define BSLS_MACROREPEAT_C11(MACRO) BSLS_MACROREPEAT_C10(MACRO), MACRO(11)
#define BSLS_MACROREPEAT_C12(MACRO) BSLS_MACROREPEAT_C11(MACRO), MACRO(12)
#define BSLS_MACROREPEAT_C13(MACRO) BSLS_MACROREPEAT_C12(MACRO), MACRO(13)
#define BSLS_MACROREPEAT_C14(MACRO) BSLS_MACROREPEAT_C13(MACRO), MACRO(14)
#define BSLS_MACROREPEAT_C15(MACRO) BSLS_MACROREPEAT_C14(MACRO), MACRO(15)
#define BSLS_MACROREPEAT_C16(MACRO) BSLS_MACROREPEAT_C15(MACRO), MACRO(16)
#define BSLS_MACROREPEAT_C17(MACRO) BSLS_MACROREPEAT_C16(MACRO), MACRO(17)
#define BSLS_MACROREPEAT_C18(MACRO) BSLS_MACROREPEAT_C17(MACRO), MACRO(18)
#define BSLS_MACROREPEAT_C19(MACRO) BSLS_MACROREPEAT_C18(MACRO), MACRO(19)
#define BSLS_MACROREPEAT_C20(MACRO) BSLS_MACROREPEAT_C19(MACRO), MACRO(20)

#define BSLS_MACROREPEAT_S0(MACRO,S)
#define BSLS_MACROREPEAT_S1(MACRO,S) MACRO(1)
#define BSLS_MACROREPEAT_S2(MACRO,S) BSLS_MACROREPEAT_S1(MACRO,S) S MACRO(2)
#define BSLS_MACROREPEAT_S3(MACRO,S) BSLS_MACROREPEAT_S2(MACRO,S) S MACRO(3)
#define BSLS_MACROREPEAT_S4(MACRO,S) BSLS_MACROREPEAT_S3(MACRO,S) S MACRO(4)
#define BSLS_MACROREPEAT_S5(MACRO,S) BSLS_MACROREPEAT_S4(MACRO,S) S MACRO(5)
#define BSLS_MACROREPEAT_S6(MACRO,S) BSLS_MACROREPEAT_S5(MACRO,S) S MACRO(6)
#define BSLS_MACROREPEAT_S7(MACRO,S) BSLS_MACROREPEAT_S6(MACRO,S) S MACRO(7)
#define BSLS_MACROREPEAT_S8(MACRO,S) BSLS_MACROREPEAT_S7(MACRO,S) S MACRO(8)
#define BSLS_MACROREPEAT_S9(MACRO,S) BSLS_MACROREPEAT_S8(MACRO,S) S MACRO(9)
#define BSLS_MACROREPEAT_S10(MACRO,S) BSLS_MACROREPEAT_S9(MACRO,S) S MACRO(10)
#define BSLS_MACROREPEAT_S11(MACRO,S) BSLS_MACROREPEAT_S10(MACRO,S) S MACRO(11)
#define BSLS_MACROREPEAT_S12(MACRO,S) BSLS_MACROREPEAT_S11(MACRO,S) S MACRO(12)
#define BSLS_MACROREPEAT_S13(MACRO,S) BSLS_MACROREPEAT_S12(MACRO,S) S MACRO(13)
#define BSLS_MACROREPEAT_S14(MACRO,S) BSLS_MACROREPEAT_S13(MACRO,S) S MACRO(14)
#define BSLS_MACROREPEAT_S15(MACRO,S) BSLS_MACROREPEAT_S14(MACRO,S) S MACRO(15)
#define BSLS_MACROREPEAT_S16(MACRO,S) BSLS_MACROREPEAT_S15(MACRO,S) S MACRO(16)
#define BSLS_MACROREPEAT_S17(MACRO,S) BSLS_MACROREPEAT_S16(MACRO,S) S MACRO(17)
#define BSLS_MACROREPEAT_S18(MACRO,S) BSLS_MACROREPEAT_S17(MACRO,S) S MACRO(18)
#define BSLS_MACROREPEAT_S19(MACRO,S) BSLS_MACROREPEAT_S18(MACRO,S) S MACRO(19)
#define BSLS_MACROREPEAT_S20(MACRO,S) BSLS_MACROREPEAT_S19(MACRO,S) S MACRO(20)

#endif // ! defined(INCLUDED_BSLS_MACROREPEAT)

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------