Boost logo

Boost :

Subject: Re: [boost] [vmd] Library Review
From: Edward Diener (eldiener_at_[hidden])
Date: 2014-09-14 16:05:55


On 9/14/2014 10:58 AM, pfultz2 wrote:
>>>> One could do better for this low-level part with registrations such as
>>>> (without a BOOST_VMD_ prefix for brevity)
>>>>
>>>> #define IDENTIFIER_CIRCLE (CIRCLE),
>>>> #define IDENTIFIER_SQUARE (SQUARE),
>>>> #define IDENTIFIER_TRIANGLE (TRIANGLE),
>>>> #define IDENTIFIER_RECTANGLE (RECTANGLE),
>>>
>>> Is the ending comma there for a reason ?
>>
>> Yes, though I think you already figured it out. The parentheses are
>> there so that you can detect that your prefix token-pasting did
>> something, the "v-identifier" is there so you can extract it, and the
>> comma is there to separate the "v-identifier" from the rest of a
>> "v-sequence".
>
> There is no need for the commas though. Its easy enough to insert them in.
> Since we take sequence of tokens first:
>
> CIRCLE SQUARE
>
> And then we concat the identifiers, which gives us this:
>
> (CIRCLE) SQUARE
>
> Then we could use this:
>
> #define APPEND_COMMA_I(...) (__VA_ARGS__),
> #define APPEND_COMMA(...) APPEND_COMMA_I __VA_ARGS__
>
> APPEND_COMMA((CIRCLE) SQUARE) // Expands to (CIRCLE), SQUARE
>
> It does require a little bit more for the implementation, however, this
> helps
> to simplify the "interface", I think.

The point is, however, that you don't know that the concatenation will
produce a tuple when you call your APPEND_COMMA. If it does not and just
produces an identifier of the form IDENTIFIER_XXX then your
APPEND_COMMA(IDENTIFIER_XXX SQUARE) will end up as 'APPEND_COMMA_I
IDENTIFIER_XXX SQUARE' which you do not want.

Actually I realized that the comma is not be needed at all in Paul's
IDENTIFIER macros above. There is already code in VMD that can split a
sequence beginning with a tuple into the beginning tuple and the rest of
the sequence ( BOOST_VMD_TUPLE ). So the logic of parsing for an
identifier at the beginning of a sequence is to start by looking for a
beginning tuple in the sequence, if not found test for an identifier
through concatenation, and if the subsequent sequence after
concatenation now starts with a beginning tuple, the code can separate
the beginning tuple from the remainder of the sequence and extract the
v-identifier.

>
>> I think it is possible. The main difficulty will be VC++ because you
>> will have to bend over backwards to get those macro-generated commas to
>> form an argument separator in a variety of situations (if I recall
>> correctly).
>
> I actually use this `MSVC_INVOKE` macro to help in those situations:
>
> #define MSVC_INVOKE BOOST_PP_CAT(MSVC_INVOKE_,
> BOOST_PP_AUTO_REC(DETAIL_MSVC_INVOKE_P, 16))
>
> #define DETAIL_MSVC_INVOKE_P(n) BOOST_PP_IS_NULLARY( MSVC_INVOKE_ ##
> n((),) )
>
> #define MSVC_INVOKE_1(macro, args) MSVC_INVOKE_I_1(macro, args)
> #define MSVC_INVOKE_2(macro, args) MSVC_INVOKE_I_2(macro, args)
> ...
> #define MSVC_INVOKE_16(macro, args) MSVC_INVOKE_I_16(macro, args)
>
> #define MSVC_INVOKE_I_1(macro, args) MSVC_INVOKE_X_1(macro args)
> #define MSVC_INVOKE_I_2(macro, args) MSVC_INVOKE_X_2(macro args)
> ...
> #define MSVC_INVOKE_I_16(macro, args) MSVC_INVOKE_X_16(macro args)
>
> #define MSVC_INVOKE_X_1(x) x
> #define MSVC_INVOKE_X_2(x) x
> ...
> #define MSVC_INVOKE_X_16(x) x

Sorry I can't follow this or udnerstand what you are doing. I don't know
what BOOST_PP_AUTO_REC does even when I look at its code <g>.

>
> Of course, I made it re-entrant which could slow down the preprocessor for
> MSVC, however, it helps simplify when I need to workaround MSVC. So if I
> need
> to call a macro with vardiac args, I can just call it like this:
>
> #define HEAD(x, ...) x
> MSVC_INVOKE(HEAD, (1,2,3,4)) // Expands to 1

Are you passing '1,2,3,4' to HEAD ?

>
> Unfortunately, there are still times where this fails as well, but most of
> the
> time this will work.
>
> Finally, when I have done this DSL like parser(like in LINQ for example), I
> would convert the string of tokens to a sequence and then process them
> afterwards using the algorithms for a sequence. So I would essentially
> transform this:
>
> #define STRING_from (from)
> #define STRING_where (where)
> #define STRING_select (select)
>
> STRING_TO_SEQ(from(x, numbers) where(x < 3) select(x * x))
>
> That then expands to:
>
> (from)((x, numbers))(where)((x < 3))(select)((x * x))

You might find this expansion easier with VMD. With Paul's suggestion
and my realization that the final comma is not needed, I will be
reprogramming the VMD v-sequence macros so that you should be able to
take a v-sequence, like your 'string' of 'from(x, numbers) where(x < 3)
select(x * x)' and break it down into its constituent v-types without
the limitations current VMD incurs. In fact I intend to add a VMD macro,
something like BOOT_VMD_SEQUENCE(vsequence) which will return all the
v-types in some way ( probably a tuple, seq, or just variadic data, I
have yet to decide ).


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk