params.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Macros for parsing and manipulating parameter lists needed for generating
  4. * mocks.
  5. *
  6. * Copyright (C) 2020, Google LLC.
  7. * Author: Brendan Higgins <[email protected]>
  8. */
  9. #ifndef _KUNIT_PARAMS_H
  10. #define _KUNIT_PARAMS_H
  11. #define NUM_VA_ARGS_IMPL(__dummy, \
  12. __1, \
  13. __2, \
  14. __3, \
  15. __4, \
  16. __5, \
  17. __6, \
  18. __7, \
  19. __8, \
  20. __9, \
  21. __10, \
  22. __11, \
  23. __12, \
  24. __13, \
  25. __14, \
  26. __15, \
  27. __16, \
  28. __nargs, args...) __nargs
  29. #define NUM_VA_ARGS(args...) NUM_VA_ARGS_IMPL(__dummy, ##args, \
  30. 16, \
  31. 15, \
  32. 14, \
  33. 13, \
  34. 12, \
  35. 11, \
  36. 10, \
  37. 9, \
  38. 8, \
  39. 7, \
  40. 6, \
  41. 5, \
  42. 4, \
  43. 3, \
  44. 2, \
  45. 1, \
  46. 0)
  47. #define CONCAT_INTERNAL(left, right) left##right
  48. #define CONCAT(left, right) CONCAT_INTERNAL(left, right)
  49. #define EMPTY()
  50. /*
  51. * Takes the name of a function style macro such as FOO() and prevents it from
  52. * being evaluated on the current pass.
  53. *
  54. * This is useful when you need to write a "recursive" macro since a macro name
  55. * becomes painted after it is pasted. If a different macro is pasted, this
  56. * different macro won't be pasted; if we then defer the evaluation of the this
  57. * "indirection macro", we can prevent the original definition from getting
  58. * painted.
  59. *
  60. * Example:
  61. * #define EXAMPLE EXPAND(FOO()) // FOO() is evaluated on 1st pass.
  62. * #define EXAMPLE EXPAND(DEFER(FOO)()) // FOO() is evaluated on the second
  63. * // pass.
  64. */
  65. #define DEFER(macro_id) macro_id EMPTY()
  66. /*
  67. * Takes the name of a function style macro such as FOO() and prevents it from
  68. * being evaluated on the current or following pass.
  69. *
  70. * This is useful when you need to DEFER inside an operation which causes an
  71. * extra pass, like IF.
  72. *
  73. * Example:
  74. * #define EXAMPLE EXPAND(FOO()) // FOO() is evaluated on 1st pass.
  75. * #define EXAMPLE EXPAND(DEFER(FOO)()) // FOO() is evaluated on the second
  76. * // pass.
  77. * #define EXAMPLE EXPAND(OBSTRUCT(FOO)()) // FOO() is evaluated on the third
  78. * // pass.
  79. */
  80. #define OBSTRUCT(macro_id) macro_id DEFER(EMPTY)()
  81. #define EXPAND_1(args...) args
  82. #define EXPAND_2(args...) EXPAND_1(EXPAND_1(args))
  83. #define EXPAND_4(args...) EXPAND_2(EXPAND_2(args))
  84. #define EXPAND_8(args...) EXPAND_4(EXPAND_4(args))
  85. #define EXPAND_16(args...) EXPAND_8(EXPAND_8(args))
  86. /*
  87. * Causes multiple evaluation passes of a macro.
  88. *
  89. * CPP is implemented as a push down automaton. It consumes a stream of tokens
  90. * and as it comes across macros, it either evaluates them and pastes the
  91. * result, or if the macro is a function macro, it pushes the macro to a stack,
  92. * it evaluates the input to the function macro, pops the state from the stack
  93. * and continues.
  94. *
  95. * This macro serves the function of making the cursor return to the beginging
  96. * of a macro that requires mulitple passes to evaluate. It is most useful when
  97. * used with DEFER(...) and OBSTRUCT(...).
  98. */
  99. #define EXPAND(args...) EXPAND_16(args)
  100. #define INC(id) INC_##id
  101. #define INC_0 1
  102. #define INC_1 2
  103. #define INC_2 3
  104. #define INC_3 4
  105. #define INC_4 5
  106. #define INC_5 6
  107. #define INC_6 7
  108. #define INC_7 8
  109. #define INC_8 9
  110. #define INC_9 10
  111. #define INC_10 11
  112. #define INC_11 12
  113. #define INC_12 13
  114. #define INC_13 14
  115. #define INC_14 15
  116. #define INC_15 16
  117. #define INC_16 17
  118. #define DEC(id) DEC_##id
  119. #define DEC_1 0
  120. #define DEC_2 1
  121. #define DEC_3 2
  122. #define DEC_4 3
  123. #define DEC_5 4
  124. #define DEC_6 5
  125. #define DEC_7 6
  126. #define DEC_8 7
  127. #define DEC_9 8
  128. #define DEC_10 9
  129. #define DEC_11 10
  130. #define DEC_12 11
  131. #define DEC_13 12
  132. #define DEC_14 13
  133. #define DEC_15 14
  134. #define DEC_16 15
  135. #define DROP_FIRST_ARG_INTERNAL(dropped, x, args...) x
  136. #define DROP_FIRST_ARG(args...) DROP_FIRST_ARG_INTERNAL(args)
  137. #define EQUAL(left, right) EQUAL_##left##_##right
  138. #define EQUAL_0_0 dropped, 1
  139. #define EQUAL_1_1 dropped, 1
  140. #define EQUAL_2_2 dropped, 1
  141. #define EQUAL_3_3 dropped, 1
  142. #define EQUAL_4_4 dropped, 1
  143. #define EQUAL_5_5 dropped, 1
  144. #define EQUAL_6_6 dropped, 1
  145. #define EQUAL_7_7 dropped, 1
  146. #define EQUAL_8_8 dropped, 1
  147. #define EQUAL_9_9 dropped, 1
  148. #define EQUAL_10_10 dropped, 1
  149. #define EQUAL_11_11 dropped, 1
  150. #define EQUAL_12_12 dropped, 1
  151. #define EQUAL_13_13 dropped, 1
  152. #define EQUAL_14_14 dropped, 1
  153. #define EQUAL_15_15 dropped, 1
  154. #define EQUAL_16_16 dropped, 1
  155. #define IS_EQUAL(left, right) DROP_FIRST_ARG(EQUAL(left, right), 0)
  156. #define NOT_INTERNAL(condition) NOT_##condition
  157. #define NOT(condition) NOT_INTERNAL(condition)
  158. #define NOT_0 1
  159. #define NOT_1 0
  160. #define IS_NOT_EQUAL(left, right) NOT(IS_EQUAL(left, right))
  161. #define EMPTY_IMPL(tokens) CONCAT(EMPTY_, tokens)
  162. #define IS_EMPTY(tokens)
  163. #define OR_INTERNAL(left, right) OR_##left##_##right
  164. #define OR(left, right) OR_INTERNAL(left, right)
  165. #define OR_0_0 0
  166. #define OR_0_1 1
  167. #define OR_1_0 1
  168. #define OR_1_1 1
  169. #define IF(condition) CONCAT(IF_, condition)
  170. #define IF_0(body)
  171. #define IF_1(body) body
  172. #define COMMA() ,
  173. #define APPLY_TOKENS_INTERNAL(tokens, yield_token, seen_token) \
  174. IF(yield_token)(IF(seen_token)(COMMA()) tokens)
  175. #define APPLY_TOKENS(tokens, yield_token, seen_token) \
  176. APPLY_TOKENS_INTERNAL(tokens, yield_token, seen_token)
  177. /*
  178. * Provides the indirection to keep the PARAM_LIST_RECURSE_INTERNAL from getting
  179. * pasted, only useful if used with DEFER(...) or OBSTRUCT(...).
  180. */
  181. #define PARAM_LIST_RECURSE_INDIRECT() PARAM_LIST_RECURSE_INTERNAL
  182. /*
  183. * Given a starting index, a number of args, a MACRO to apply, and a list of
  184. * types (with at least one element) this will call MACRO with the first type in
  185. * the list and index; it will then call itself again on all remaining types, if
  186. * any, while incrementing index, and decrementing nargs.
  187. *
  188. * Assumes nargs is the number of types in the list.
  189. */
  190. #define PARAM_LIST_RECURSE_INTERNAL(index, \
  191. nargs, \
  192. MACRO, \
  193. FILTER, \
  194. context, \
  195. seen_token, \
  196. type, \
  197. args...) \
  198. APPLY_TOKENS(MACRO(context, type, index), \
  199. FILTER(context, type, index), \
  200. seen_token) \
  201. IF(IS_NOT_EQUAL(nargs, 1)) \
  202. (OBSTRUCT(PARAM_LIST_RECURSE_INDIRECT)() \
  203. (INC(index), DEC(nargs), \
  204. MACRO, FILTER, context, \
  205. OR(seen_token, FILTER(context, type, index)), \
  206. args))
  207. #define PARAM_LIST_RECURSE(index, nargs, MACRO, FILTER, context, args...) \
  208. IF(IS_NOT_EQUAL(nargs, 0)) \
  209. (OBSTRUCT(PARAM_LIST_RECURSE_INTERNAL)(index, \
  210. nargs, \
  211. MACRO, \
  212. FILTER, \
  213. context, \
  214. 0, \
  215. args))
  216. #define FILTER_NONE(context, type, index) 1
  217. #define FILTER_INDEX_INTERNAL(index_to_drop, type, index) \
  218. IS_NOT_EQUAL(index, index_to_drop)
  219. #define FILTER_INDEX(index_to_drop, type, index) \
  220. FILTER_INDEX_INTERNAL(index_to_drop, type, index)
  221. /*
  222. * Applies a MACRO which takes a type and the index of the type and outputs a
  223. * sequence of tokens to a list of types.
  224. */
  225. #define FOR_EACH_PARAM(MACRO, FILTER, context, args...) \
  226. EXPAND(PARAM_LIST_RECURSE(0,\
  227. NUM_VA_ARGS(args),\
  228. MACRO,\
  229. FILTER,\
  230. context,\
  231. args))
  232. #define PRODUCE_TYPE_AND_ARG(context, type, index) type arg##index
  233. #define PARAM_LIST_FROM_TYPES(args...) \
  234. FOR_EACH_PARAM(PRODUCE_TYPE_AND_ARG, \
  235. FILTER_NONE, \
  236. not_used, \
  237. args)
  238. #define PRODUCE_TYPE_NAME(context, type, index) #type
  239. #define TYPE_NAMES_FROM_TYPES(handle_index, args...) \
  240. FOR_EACH_PARAM(PRODUCE_TYPE_NAME, \
  241. FILTER_INDEX, \
  242. handle_index, \
  243. args)
  244. #define PRODUCE_PTR_TO_ARG(context, type, index) &arg##index
  245. #define PTR_TO_ARG_FROM_TYPES(handle_index, args...) \
  246. FOR_EACH_PARAM(PRODUCE_PTR_TO_ARG, \
  247. FILTER_INDEX, \
  248. handle_index, \
  249. args)
  250. #define PRODUCE_MATCHER_AND_ARG(ctrl_index, type, index) \
  251. IF(IS_EQUAL(index, ctrl_index))(struct mock *arg##ctrl_index) \
  252. IF(IS_NOT_EQUAL(index, ctrl_index))( \
  253. struct mock_param_matcher *arg##index)
  254. #define MATCHER_PARAM_LIST_FROM_TYPES(ctrl_index, args...) \
  255. FOR_EACH_PARAM(PRODUCE_MATCHER_AND_ARG, \
  256. FILTER_NONE, \
  257. ctrl_index, \
  258. args)
  259. #define PRODUCE_ARG(context, type, index) arg##index
  260. #define ARG_NAMES_FROM_TYPES(ctrl_index, args...) \
  261. FOR_EACH_PARAM(PRODUCE_ARG, \
  262. FILTER_INDEX, \
  263. ctrl_index, \
  264. args)
  265. #define PRODUCE_ARRAY_ACCESSOR(context, type, index) *((type *) params[index])
  266. #define ARRAY_ACCESSORS_FROM_TYPES(args...) \
  267. FOR_EACH_PARAM(PRODUCE_ARRAY_ACCESSOR, \
  268. FILTER_NONE, \
  269. not_used, \
  270. args)
  271. #endif /* _KUNIT_PARAMS_H */