preprocessor programming

25
Preprocessor programming 2013. 08. 23. 최재영

Upload: lactrious

Post on 28-Nov-2014

182 views

Category:

Engineering


2 download

DESCRIPTION

c++ preprocessor programming for explanation of boost pp

TRANSCRIPT

Page 1: Preprocessor Programming

Preprocessor programming

2013. 08. 23.

최재영

Page 2: Preprocessor Programming

Motivation

• Don’t Repeat Yourself!

2

template <class T>DoAsync(void (T::*member)()) {}template <class T, class A1>DoAsync(void (T::*member)(), A1 a1) {}template <class T, class A1, class A2>DoAsync(void (T::*member)(), A1 a1, A2 a2) {}template <class T, class A1, class A2, class A3>DoAsync(void (T::*member)(), A1 a1, A2 a2, A3 a3) {}template <class T, class A1, class A2, class A3, class A4>DoAsync(void (T::*member)(), A1 a1, A2 a2, A3 a3, A4 a4) {}

enum SomeType {TypeA,TypeB,

};

const TCHAR* GetSomeTypeName(SomeType type) {if (type == TypeA) return _T("TypeA");if (type == TypeB) return _T("TypeB");return _T("");

}

Page 3: Preprocessor Programming

Why?

• generate code that cannot be generated by template

• or generate boilerplate template code

3

concat token

repetition

multi-pass generation

a ## b

#include "repl_a.h"#include "spec.h"#include "repl_b.h"#include "spec.h"

#define TARGET "spec.h"#include "iteration.h"

#define DECL(name) \template <REPEAT(MAX_SIZE, class T)>

Page 4: Preprocessor Programming

흐름4

X-Macro

repetition

Boost PP

horizontalvertical

Page 5: Preprocessor Programming

Fundamentals5

// object-like macro

#define <identifier> <replacement token list>

// function-like macro, note parameters

#define <identifier>(<parameter list>) <replacement token list>

// local macro

#define <identifier>

/* do something */

#undef <identifier>

• Macro expansion in the preprocessor is entirely functional.

But the preprocessor disallows recursion.

Page 6: Preprocessor Programming

Fundamentals (cont.)6

// reentrancy problem

#define CONCAT(a, b) a ## b

#define AB(x, y) CONCAT(x, y)

CONCAT(A, B(p, q)) // CONCAT(p, q), not pq

// solving the one-depth reentrancy problem

#define CONCAT2(a, b) a ## b

#define AB(x, y) CONCAT(x, y)

#define CONCAT(a, b) CONCAT2(a, b)

CONCAT(A, B(p, q)) // pq

• How many recursion-depth does it support?

• How many case does it define?

Page 7: Preprocessor Programming

X-Macro

• generating repeating code structures at compile time

7

enum SomeType {ST_SOME,ST_OTHER

};

inline const TCHAR* GetNameFromSomeType(SomeType type) {if (type == ST_SOME) return _T("ST_SOME");if (type == ST_OTHER) return _T("ST_OTHER");return _T("");

}

inline SomeType GetSomeTypeFromName(const TCHAR* str) {if (_tcsicmp(str, _T("ST_SOME") == 0) return ST_SOME;if (_tcsicmp(str, _T("ST_OTHER") == 0) return ST_OTHER;return static_cast<SomeType>(-1);

}

Page 8: Preprocessor Programming

X-Macro (cont.)8

ENUM_BEGIN(SomeType)ENUM(ST_SOME)ENUM(ST_OTHER)

ENUM_END(SomeType)

#define ENUM_BEGIN(name) enum name {#define ENUM(name) name,#define ENUM_END(name) };

#define ENUM_BEGIN(name) \inline const TCHAR* GetNameFrom##name##(name type) {

#define ENUM(name) if (type == name) return _T(#name);#define ENUM_END(name) return _T(""); }

#define ENUM_BEGIN(name) \inline name Get##name##FromName(const TCHAR* str) {

#define ENUM(name) if (_tcsicmp(str, #name) == 0) return name;#define ENUM_END(name) return static_cast<name>(-1); }

sometype_spec.h

enum_decl_gen.h

enum_to_str_gen.h

str_to_enum_gen.h

Page 9: Preprocessor Programming

X-Macro (cont.)9

#include "enum_decl_gen.h"#include "sometype_spec.h"

enums.h

#include "enum_to_str_gen.h"#include "sometype_spec.h"

#include "enum_gen_reset.h"

#include "str_to_enum_gen.h"#include "sometype_spec.h"

enums.cpp

#undef ENUM_BEGIN#undef ENUM#undef ENUM_END

enum_gen_reset.h

Page 10: Preprocessor Programming

Repetition

• horizontal repetition

• vertical repetition

10

template <class T>void DoAsync(...);

template <class T, class A0>void DoAsync(...);

template <class T, class A0, class A1>void DoAsync(...);

template <class T, class A0, class A1, class A2>void DoAsync(...);

template <class T, class A0, class A1, class A2, class A3>void DoAsync(...);

vertical

horizontal

Page 11: Preprocessor Programming

Horizontal Repetition (cont.)

• the preprocessor disallows recursion.

• all cases should be defined.

11

#define REPEAT_1(m) m(0)

#define REPEAT_2(m) REPEAT_1(m), m(1)

#define REPEAT_3(m) REPEAT_2(m), m(2)

#define REPEAT_4(m) REPEAT_3(m), m(3)

#define REPEAT_5(m) REPEAT_4(m), m(4)

// ...

#define REPEAT(c, m) CONCAT(REPEAT_, c)(m)

chaining

end condition

case selector

Page 12: Preprocessor Programming

Horizontal Repetition (cont.)12

generator#define REPEAT_PARAM(n) class T ## n

template <class R, REPEAT(4, REPEAT_PARAM)>

struct test_t {}; repeat count

template <class R, class T0, class T1, class T2, class T3>

struct test_t {}; repeated

expand!

Page 13: Preprocessor Programming

Vertical Repetition (cont.)

• macro state & self-include

13

#if !defined(CURRENT)# define CURRENT 0# include "repeater.h"#elif CURRENT < SIZE# if CURRENT == 0# undef CURRENT# define CURRENT 1# elif CURRENT == 1# undef CURRENT# define CURRENT 2

// ...

# endif# include TARGET# include "repeater.h"#else#endif

repeater.h

define initial state

self-include

self-include

target-include

state-machine

repeater.h(TARGET, SIZE)

Page 14: Preprocessor Programming

#ifndef REPEAT_PARAM

#define REPEAT_PARAM(n) class T ## n

#endif

template <class R, REPEAT(CURRENT, REPEAT_PARAM)>

struct test_t {};

Vertical Repetition (cont.)14

spec.h

iteration count

#define TARGET "spec.h"#define SIZE 3#include "repeater.h"

main.cpp

set macro parameter

call macro file function

Page 15: Preprocessor Programming

Is it end?15

template <class T0, class T1, class T2>struct tiny_size {};

template <class T0, class T1>struct tiny_size<T0, T1, none> {};

template <class T0>struct tiny_size<T0, none, none> {};

template <>struct tiny_size<none, none, none> {};

comma problem

need to sub function

seperate original template & partial specialization generator

Page 16: Preprocessor Programming

COMMA_IF_NONZERO (helper)16

#define COMMA_IF_NONZERO_0

#define COMMA_IF_NONZERO_1 ,

#define COMMA_IF_NONZERO_2 ,

#define COMMA_IF_NONZERO_3 ,

#define COMMA_IF_NONZERO_4 ,

#define COMMA_IF_NONZERO_5 ,

#define COMMA_IF_NONZERO(n) CONCAT(COMMA_IF_NONZERO_, n)

all cases should be defined!

Page 17: Preprocessor Programming

SUB (helper)17

// ...

#define SUB_33 0

#define SUB_20 2

#define SUB_21 1

#define SUB_22 0

#define SUB_10 1

#define SUB_11 0

#define SUB_00 0

#define SUB(a, b) CONCAT(CONCAT(SUB_, a), b)

all cases should be defined ... ?

Page 18: Preprocessor Programming

Vertical Repetition (cont.)

• size ≠ limit

18

// ...

#elif CURRENT < LIMIT# if CURRENT == 0# undef CURRENT# define CURRENT 1

// ...

repeater.h

repeater.h(TARGET, SIZE, LIMIT)

Page 19: Preprocessor Programming

Vertical Repetition (cont.)19

main.cpp

#define SIZE 3template <class RCOMMA_IF_NONZERO(SIZE)

REPEAT(SIZE, REPEAT_PARAM)>struct test{};

#define TARGET "spec.h"#define LIMIT SUB(SIZE, 1)

#include "repeater.h"

template <class RCOMMA_IF_NONZERO(CURRENT)REPEAT(CURRENT, REPEAT_PARAM)>

struct test<RCOMMA_IF_NONZERO(CURRENT)REPEAT(CURRENT, REPEAT_VAR)COMMA_IF_NONZERO(SUB(SIZE, CURRENT))REPEAT(SUB(SIZE, CURRENT), REPEAT_NONE)>

{};

spec.h

file iteration

generate partial specialization

generate original template

Page 20: Preprocessor Programming

Vertical Repetition (cont.)20

• Local iteration: using macro state

#if !defined(IS_REPEATING)

# define IS_REPEATING 1

# include "repeater.h"

#else

# if !defined(CURRENT)

# define CURRENT 0

# include "repeater.h"

# elif CURRENT <= LIMIT

// ...

# else

# undef IS_REPEATING

# endif

#endif

initial state

iterating state

Page 21: Preprocessor Programming

Vertical Repetition (cont.)21

#if !defined(IS_REPEATING)# define SIZE 3template <class R

COMMA_IF_NONZERO(SIZE)REPEAT(CURRENT, REPEAT_PARAM)>

struct test {};# define TARGET "test.h"# define LIMIT SUB(SIZE, 1)# include "repeater.h"#elsetemplate <class R

COMMA_IF_NONZERO(CURRENT)REPEAT(CURRENT, REPEAT_PARAM)>

struct test<RCOMMA_IF_NONZERO(CURRENT)REPEAT(CURRENT, REPEAT_VAR)COMMA_IF_NONZERO(SUB(SIZE, CURRENT))REPEAT(SUB(SIZE, CURRENT), REPEAT_NONE)> {};

#endif

iterating state

initial state

repetition entry-point

Page 22: Preprocessor Programming

boost pp

• boost preprocess library

– BOOST_PP_CAT

– BOOST_PP_ENUM_PARAMS

– BOOST_PP_REPEAT

– BOOST_PP_COMMA_IF

– BOOST_PP_SUB

– BOOST_PP_DEC

– BOOST_PP_WHILE

– BOOST_PP_ITERATE

22

Page 23: Preprocessor Programming

boost pp (cont.)

• many predefined macros functions

– Arithmetic, Logical, and Comparison Operations

– Control Structures

– Token Pasting(argument selection)

– Data Types(sequence, tuple, array, list)

• well-optimized expand complexity

23

# define BOOST_PP_NODE_ENTRY_256(p) \BOOST_PP_NODE_128(p)(p)(p)(p)(p)(p)(p)(p)

# define BOOST_PP_NODE_ENTRY_128(p) \BOOST_PP_NODE_64(p)(p)(p)(p)(p)(p)(p)

// ...# define BOOST_PP_NODE_ENTRY_2(p) BOOST_PP_NODE_1(p)

Page 24: Preprocessor Programming

boost pp (cont.)

• supports 256 reentrancy

• supports 3 dimension (concurrently expandable count)

24

# define BOOST_PP_DEC_0 0# define BOOST_PP_DEC_1 0// ...# define BOOST_PP_DEC_255 254# define BOOST_PP_DEC_256 255

# define BOOST_PP_REPEAT_1(c, m, d) BOOST_PP_REPEAT_1_I(c, m, d)# define BOOST_PP_REPEAT_2(c, m, d) BOOST_PP_REPEAT_2_I(c, m, d)# define BOOST_PP_REPEAT_3(c, m, d) BOOST_PP_REPEAT_3_I(c, m, d)

Page 25: Preprocessor Programming

Summary

• Don't repeat yourself!

• reduce boilerplate code using preprocess programming

• but, your compile time is also boosted!

25