1 2 // (C) Copyright Edward Diener 2011-2015 3 // Use, modification and distribution are subject to the Boost Software License, 4 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt). 6 7 #if !defined(BOOST_VMD_TEST_DOC_EXAMPLE_SWITCH_HPP) 8 #define BOOST_VMD_TEST_DOC_EXAMPLE_SWITCH_HPP 9 10 //[ example_switch 11 12 #include <boost/vmd/detail/setup.hpp> 13 14 #if BOOST_PP_VARIADICS 15 16 #include <boost/preprocessor/cat.hpp> 17 #include <boost/preprocessor/arithmetic/inc.hpp> 18 #include <boost/preprocessor/comparison/equal.hpp> 19 #include <boost/preprocessor/control/expr_iif.hpp> 20 #include <boost/preprocessor/control/iif.hpp> 21 #include <boost/preprocessor/control/while.hpp> 22 #include <boost/preprocessor/tuple/elem.hpp> 23 #include <boost/preprocessor/tuple/enum.hpp> 24 #include <boost/preprocessor/facilities/expand.hpp> 25 #include <boost/preprocessor/tuple/replace.hpp> 26 #include <boost/preprocessor/tuple/size.hpp> 27 #include <boost/preprocessor/variadic/to_tuple.hpp> 28 #include <boost/preprocessor/variadic/size.hpp> 29 #include <boost/vmd/equal.hpp> 30 #include <boost/vmd/identity.hpp> 31 #include <boost/vmd/is_empty.hpp> 32 33 /* 34 35 State index into state values 36 37 */ 38 39 #define BOOST_VMD_SWITCH_STATE_ELEM_INDEX 2 40 #define BOOST_VMD_SWITCH_STATE_ELEM_DEFAULT 4 41 #define BOOST_VMD_SWITCH_STATE_ELEM_RESULT 5 42 43 /* 44 45 Retrieve the state value, never changes 46 47 */ 48 49 #define BOOST_VMD_SWITCH_STATE_GET_VALUE(state) \ 50 BOOST_PP_TUPLE_ELEM(0,state) \ 51 /**/ 52 53 /* 54 55 Retrieve the state tuple of values, never changes 56 57 */ 58 59 #define BOOST_VMD_SWITCH_STATE_GET_CHOICES(state) \ 60 BOOST_PP_TUPLE_ELEM(1,state) \ 61 /**/ 62 63 /* 64 65 Retrieve the state index 66 67 */ 68 69 #define BOOST_VMD_SWITCH_STATE_GET_INDEX(state) \ 70 BOOST_PP_TUPLE_ELEM(2,state) \ 71 /**/ 72 73 /* 74 75 Retrieve the state tuple of values size, never changes 76 77 */ 78 79 #define BOOST_VMD_SWITCH_STATE_GET_SIZE(state) \ 80 BOOST_PP_TUPLE_ELEM(3,state) \ 81 /**/ 82 83 /* 84 85 Retrieve the state default tuple 86 87 */ 88 89 #define BOOST_VMD_SWITCH_STATE_GET_DEFAULT(state) \ 90 BOOST_PP_TUPLE_ELEM(4,state) \ 91 /**/ 92 93 /* 94 95 Retrieve the state result tuple 96 97 */ 98 99 #define BOOST_VMD_SWITCH_STATE_GET_RESULT(state) \ 100 BOOST_PP_TUPLE_ELEM(5,state) \ 101 /**/ 102 103 /* 104 105 Retrieve the current value tuple 106 107 */ 108 109 #define BOOST_VMD_SWITCH_STATE_GET_CURRENT_CHOICE(state) \ 110 BOOST_PP_TUPLE_ELEM \ 111 ( \ 112 BOOST_VMD_SWITCH_STATE_GET_INDEX(state), \ 113 BOOST_VMD_SWITCH_STATE_GET_CHOICES(state) \ 114 ) \ 115 /**/ 116 117 /* 118 119 Expands to the state 120 121 value = value to compare against 122 tuple = choices as a tuple of values 123 size = size of tuple of values 124 125 None of these ever change in the WHILE state 126 127 */ 128 129 #define BOOST_VMD_SWITCH_STATE_EXPAND(value,tuple,size) \ 130 (value,tuple,0,size,(0,),(,)) \ 131 /**/ 132 133 /* 134 135 Expands to the WHILE state 136 137 The state to our WHILE consists of a tuple of elements: 138 139 1: value to compare against 140 2: tuple of values. Each value is a value/macro pair or if the default just a macro 141 3: index into the values 142 4: tuple for default macro. 0 means no default macro, 1 means default macro and then second value is the default macro. 143 5: tuple of result matched. Emptiness means no result yet specified, 0 means no match, 1 means match and second value is the matching macro. 144 145 */ 146 147 #define BOOST_VMD_SWITCH_STATE(value,...) \ 148 BOOST_VMD_SWITCH_STATE_EXPAND \ 149 ( \ 150 value, \ 151 BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__), \ 152 BOOST_PP_VARIADIC_SIZE(__VA_ARGS__) \ 153 ) \ 154 /**/ 155 156 /* 157 158 Sets the state upon a successful match. 159 160 macro = is the matching macro found 161 162 */ 163 164 #define BOOST_VMD_SWITCH_OP_SUCCESS(d,state,macro) \ 165 BOOST_PP_TUPLE_REPLACE_D \ 166 ( \ 167 d, \ 168 state, \ 169 BOOST_VMD_SWITCH_STATE_ELEM_RESULT, \ 170 (1,macro) \ 171 ) \ 172 /**/ 173 174 /* 175 176 Sets the state upon final failure to find a match. 177 178 def = default tuple macro, ignored 179 180 */ 181 182 #define BOOST_VMD_SWITCH_OP_FAILURE(d,state,def) \ 183 BOOST_PP_TUPLE_REPLACE_D \ 184 ( \ 185 d, \ 186 state, \ 187 BOOST_VMD_SWITCH_STATE_ELEM_RESULT, \ 188 (0,) \ 189 ) \ 190 /**/ 191 192 /* 193 194 Increments the state index into the tuple values 195 196 */ 197 198 #define BOOST_VMD_SWITCH_OP_UPDATE_INDEX(d,state) \ 199 BOOST_PP_TUPLE_REPLACE_D \ 200 ( \ 201 d, \ 202 state, \ 203 BOOST_VMD_SWITCH_STATE_ELEM_INDEX, \ 204 BOOST_PP_INC(BOOST_VMD_SWITCH_STATE_GET_INDEX(state)) \ 205 ) \ 206 /**/ 207 208 /* 209 210 Choose our current value's macro as our successful match 211 212 tuple = current tuple to test 213 214 */ 215 216 #define BOOST_VMD_SWITCH_OP_TEST_CURRENT_VALUE_MATCH(d,state,tuple) \ 217 BOOST_VMD_SWITCH_OP_SUCCESS(d,state,BOOST_PP_TUPLE_ELEM(1,tuple)) \ 218 /**/ 219 220 /* 221 222 Update our state index 223 224 tuple = current tuple to test, ignored 225 226 */ 227 228 #define BOOST_VMD_SWITCH_OP_TEST_CURRENT_VALUE_UPDATE_INDEX(d,state,tuple) \ 229 BOOST_VMD_SWITCH_OP_UPDATE_INDEX(d,state) \ 230 /**/ 231 232 /* 233 234 Test our current value against our value to compare against 235 236 tuple = current tuple to test 237 238 */ 239 240 #define BOOST_VMD_SWITCH_OP_TEST_CURRENT_VALUE(d,state,tuple) \ 241 BOOST_PP_IIF \ 242 ( \ 243 BOOST_VMD_EQUAL_D \ 244 ( \ 245 d, \ 246 BOOST_VMD_SWITCH_STATE_GET_VALUE(state), \ 247 BOOST_PP_TUPLE_ELEM(0,tuple) \ 248 ), \ 249 BOOST_VMD_SWITCH_OP_TEST_CURRENT_VALUE_MATCH, \ 250 BOOST_VMD_SWITCH_OP_TEST_CURRENT_VALUE_UPDATE_INDEX \ 251 ) \ 252 (d,state,tuple) \ 253 /**/ 254 255 /* 256 257 Set our default macro and update the index in our WHILE state 258 259 tuple = current tuple to test 260 261 */ 262 263 #if BOOST_VMD_MSVC 264 265 #define BOOST_VMD_SWITCH_OP_TEST_CURRENT_CREATE_DEFAULT_NN(number,name) \ 266 (number,name) \ 267 /**/ 268 269 #define BOOST_VMD_SWITCH_OP_TEST_CURRENT_CREATE_DEFAULT(d,state,tuple) \ 270 BOOST_VMD_SWITCH_OP_UPDATE_INDEX \ 271 ( \ 272 d, \ 273 BOOST_PP_TUPLE_REPLACE_D \ 274 ( \ 275 d, \ 276 state, \ 277 BOOST_VMD_SWITCH_STATE_ELEM_DEFAULT, \ 278 BOOST_VMD_SWITCH_OP_TEST_CURRENT_CREATE_DEFAULT_NN(1,BOOST_PP_TUPLE_ENUM(tuple)) \ 279 ) \ 280 ) \ 281 /**/ 282 283 #else 284 285 #define BOOST_VMD_SWITCH_OP_TEST_CURRENT_CREATE_DEFAULT(d,state,tuple) \ 286 BOOST_VMD_SWITCH_OP_UPDATE_INDEX \ 287 ( \ 288 d, \ 289 BOOST_PP_TUPLE_REPLACE_D \ 290 ( \ 291 d, \ 292 state, \ 293 BOOST_VMD_SWITCH_STATE_ELEM_DEFAULT, \ 294 (1,BOOST_PP_TUPLE_ENUM(tuple)) \ 295 ) \ 296 ) \ 297 /**/ 298 299 #endif 300 301 /* 302 303 If our current value is a default macro, just set the default macro, 304 else test our current value. 305 306 tuple = current tuple to test 307 308 */ 309 310 #define BOOST_VMD_SWITCH_OP_TEST_CURRENT_TUPLE(d,state,tuple) \ 311 BOOST_PP_IIF \ 312 ( \ 313 BOOST_PP_EQUAL_D \ 314 ( \ 315 d, \ 316 BOOST_PP_TUPLE_SIZE(tuple), \ 317 1 \ 318 ), \ 319 BOOST_VMD_SWITCH_OP_TEST_CURRENT_CREATE_DEFAULT, \ 320 BOOST_VMD_SWITCH_OP_TEST_CURRENT_VALUE \ 321 ) \ 322 (d,state,tuple) \ 323 /**/ 324 325 /* 326 327 Test the current value in our tuple of values 328 329 */ 330 331 #define BOOST_VMD_SWITCH_OP_TEST_CURRENT(d,state) \ 332 BOOST_VMD_SWITCH_OP_TEST_CURRENT_TUPLE \ 333 ( \ 334 d, \ 335 state, \ 336 BOOST_VMD_SWITCH_STATE_GET_CURRENT_CHOICE(state) \ 337 ) \ 338 /**/ 339 340 /* 341 342 Choose the default macro as our successful match 343 344 def = default tuple consisting of just the default macro name 345 346 */ 347 348 #define BOOST_VMD_SWITCH_OP_DEFAULT_RET_CHOSEN(d,state,def) \ 349 BOOST_VMD_SWITCH_OP_SUCCESS \ 350 ( \ 351 d, \ 352 state, \ 353 BOOST_PP_TUPLE_ELEM(1,def) \ 354 ) \ 355 /**/ 356 357 /* 358 359 If the default macro exists, choose it else indicate no macro was found 360 361 def = default tuple consisting of just the default macro name 362 363 */ 364 365 #define BOOST_VMD_SWITCH_OP_DEFAULT_RET(d,state,def) \ 366 BOOST_PP_IIF \ 367 ( \ 368 BOOST_PP_TUPLE_ELEM(0,def), \ 369 BOOST_VMD_SWITCH_OP_DEFAULT_RET_CHOSEN, \ 370 BOOST_VMD_SWITCH_OP_FAILURE \ 371 ) \ 372 (d,state,def) \ 373 /**/ 374 375 /* 376 377 Try to choose the default macro if it exists 378 379 */ 380 381 #define BOOST_VMD_SWITCH_OP_DEFAULT(d,state) \ 382 BOOST_VMD_SWITCH_OP_DEFAULT_RET \ 383 ( \ 384 d, \ 385 state, \ 386 BOOST_VMD_SWITCH_STATE_GET_DEFAULT(state) \ 387 ) \ 388 /**/ 389 390 /* 391 392 WHILE loop operation 393 394 Check for the next value match or try to choose the default if all matches have been checked 395 396 */ 397 398 #define BOOST_VMD_SWITCH_OP(d,state) \ 399 BOOST_PP_IIF \ 400 ( \ 401 BOOST_PP_EQUAL_D \ 402 ( \ 403 d, \ 404 BOOST_VMD_SWITCH_STATE_GET_INDEX(state), \ 405 BOOST_VMD_SWITCH_STATE_GET_SIZE(state) \ 406 ), \ 407 BOOST_VMD_SWITCH_OP_DEFAULT, \ 408 BOOST_VMD_SWITCH_OP_TEST_CURRENT \ 409 ) \ 410 (d,state) \ 411 /**/ 412 413 /* 414 415 WHILE loop predicate 416 417 Continue the WHILE loop if a result has not yet been specified 418 419 */ 420 421 #define BOOST_VMD_SWITCH_PRED(d,state) \ 422 BOOST_VMD_IS_EMPTY \ 423 ( \ 424 BOOST_PP_TUPLE_ELEM \ 425 ( \ 426 0, \ 427 BOOST_VMD_SWITCH_STATE_GET_RESULT(state) \ 428 ) \ 429 ) \ 430 /**/ 431 432 /* 433 434 Invokes the function-like macro 435 436 macro = function-like macro name 437 tparams = tuple of macro parameters 438 439 */ 440 441 #define BOOST_VMD_SWITCH_PROCESS_INVOKE_MACRO(macro,tparams) \ 442 BOOST_PP_EXPAND(macro tparams) \ 443 /**/ 444 445 /* 446 447 Processes our WHILE loop result 448 449 callp = tuple of parameters for the called macro 450 result = tuple. The first tuple element is 0 451 if no macro has been found or 1 if a macro 452 has been found. If 1 the second element is 453 the name of a function-like macro 454 455 */ 456 457 #define BOOST_VMD_SWITCH_PROCESS(callp,result) \ 458 BOOST_PP_EXPR_IIF \ 459 ( \ 460 BOOST_PP_TUPLE_ELEM(0,result), \ 461 BOOST_VMD_SWITCH_PROCESS_INVOKE_MACRO \ 462 ( \ 463 BOOST_PP_TUPLE_ELEM(1,result), \ 464 callp \ 465 ) \ 466 ) \ 467 /**/ 468 469 /* 470 471 Use BOOST_VMD_SWITCH_IDENTITY to pass a fixed value instead 472 of a function-like macro as the second element of 473 any tuple of the variadic parameters, or as the default 474 value, to BOOST_VMD_SWITCH. 475 476 */ 477 478 #if BOOST_VMD_MSVC 479 #define BOOST_VMD_SWITCH_IDENTITY(item) BOOST_PP_CAT(BOOST_VMD_IDENTITY(item),) 480 #else 481 #define BOOST_VMD_SWITCH_IDENTITY BOOST_VMD_IDENTITY 482 #endif 483 484 /* 485 486 Switch macro 487 488 Parameters are: 489 490 value = value to compare against. May be any VMD data value. 491 callp = tuple of parameters for the called macro 492 variadic parameters = each parameter must be a tuple. 493 Each tuple consists of a two-element tuple. The first element is 494 a value, which may be any VMD data value, and the second element 495 is the name of a function-like macro to be called if the value 496 is equal to the value to compare against. For a default value 497 the tuple is a single-element tuple which contains the name of 498 a function-like macro to be called if no other value matches. 499 500 */ 501 502 #define BOOST_VMD_SWITCH(value,callp,...) \ 503 BOOST_VMD_SWITCH_PROCESS \ 504 ( \ 505 callp, \ 506 BOOST_VMD_SWITCH_STATE_GET_RESULT \ 507 ( \ 508 BOOST_PP_WHILE \ 509 ( \ 510 BOOST_VMD_SWITCH_PRED, \ 511 BOOST_VMD_SWITCH_OP, \ 512 BOOST_VMD_SWITCH_STATE(value,__VA_ARGS__) \ 513 ) \ 514 ) \ 515 ) \ 516 /**/ 517 518 #endif /* BOOST_PP_VARIADICS */ 519 520 //] 521 522 #endif /* BOOST_VMD_TEST_DOC_EXAMPLE_SWITCH_HPP */ 523