problem with BOOST_PP_IS_EMPTY macro

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

problem with BOOST_PP_IS_EMPTY macro

Serguei Kolos
Hello

Using the BOOST_PP_IS_EMPTY macro with string literal as parameter
causes compiler warning:
warning: pasting "BOOST_PP_IS_EMPTY_DEF_" and ""AA"" does not give a valid preprocessing token

In order to avoid this warning I have reimplemented this macro
as it is shown below. Could something similar be implemented by
the preprocessor library.

Cheers,
Sergei


#include <boost/preprocessor/if.hpp>
#include <boost/preprocessor/tuple.hpp>
#include <boost/preprocessor/facilities/is_empty.hpp>

#define MY_BOOST_PP_IS_EMPTY(x)                                 MY_BOOST_PP_IS_EMPTY_I(MY_BOOST_PP_IS_EMPTY_HELPER x)
#define MY_BOOST_PP_IS_EMPTY_I(contents)                        MY_BOOST_PP_IS_EMPTY_II( contents() )
#define MY_BOOST_PP_IS_EMPTY_II(contents)                       MY_BOOST_PP_IS_EMPTY_III( contents )
#define MY_BOOST_PP_IS_EMPTY_III(contents)                      BOOST_PP_TUPLE_ELEM( 2, 0, ( MY_BOOST_PP_IS_EMPTY_DEF_ ## contents ) )
#define MY_BOOST_PP_IS_EMPTY_HELPER()                           MY_BOOST_PP_IS_EMPTY_TRUE
#define MY_BOOST_PP_IS_EMPTY_DEF_MY_BOOST_PP_IS_EMPTY_TRUE      1 ,
#define MY_BOOST_PP_IS_EMPTY_DEF_MY_BOOST_PP_IS_EMPTY_HELPER    0 ,

#define TEST_CASE_1( x )        BOOST_PP_IF( BOOST_PP_IS_EMPTY( x ), is empty, x )
#define TEST_CASE_2( x )        BOOST_PP_IF( MY_BOOST_PP_IS_EMPTY( x ), is empty, x )


TEST_CASE_1( "" )
TEST_CASE_1( "AA" )
TEST_CASE_1( AA )
TEST_CASE_1(  )

TEST_CASE_2( "" )
TEST_CASE_2( "AA" )
TEST_CASE_2( AA )
TEST_CASE_2( )

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: problem with BOOST_PP_IS_EMPTY macro

Paul Mensonides
 

> -----Original Message-----
> From: [hidden email]
> [mailto:[hidden email]] On Behalf Of Serguei KOLOS
> Sent: Tuesday, February 21, 2006 12:42 AM
> To: [hidden email]
> Subject: [boost] problem with BOOST_PP_IS_EMPTY macro
>
> Hello
>
> Using the BOOST_PP_IS_EMPTY macro with string literal as
> parameter causes compiler warning:
> warning: pasting "BOOST_PP_IS_EMPTY_DEF_" and ""AA"" does not
> give a valid preprocessing token

That macro is 1) not a library interface (so why are you using it?) and 2) is
not a general purpose emptiness detector (there is no such thing).  There are
very specific constraints on what the input is supposed to be.

> #include <boost/preprocessor/if.hpp>
> #include <boost/preprocessor/tuple.hpp>
> #include <boost/preprocessor/facilities/is_empty.hpp>
>
> #define MY_BOOST_PP_IS_EMPTY(x)                              
>   MY_BOOST_PP_IS_EMPTY_I(MY_BOOST_PP_IS_EMPTY_HELPER x)

First, this will fail if 'x' is a parenthesized expression.  I.e. if 'x' is ()
or (a) or (a, b), etc..  It will also fail if 'x' ends with a function-like
macro name.

Second, passing nothing--as in TEST_CASE_1( ) and TEST_CASE_2( )--is results in
undefined behavior in current C++ (which will give you warnings on many
preprocessors).

Third, even with placemarkers from C99 (well-defined semantics for empty
arguments), you still cannot generally test emptiness.  Trust me, there is *no*
way to do it.  The best that you can do is to contrain the input to a subset of
non-pathological input.

The macros in the library, IS_EMPTY, IS_1, and IS_EMPTY_OR_1 are all designed
for a very specific purpose:  testing flags such as:

#define CONFIG_A
#define CONFIG_B 1
#define CONFIG_C 0

IS_EMPTY(CONFIG_A) // 1
IS_EMPTY(CONFIG_B) // 0
IS_EMPTY(CONFIG_C) // 0

IS_1(CONFIG_A) // 0
IS_1(CONFIG_B) // 1
IS_1(CONFIG_C) // 0

IS_EMPTY_OR_1(CONFIG_A) // 1
IS_EMPTY_OR_1(CONFIG_B) // 1
IS_EMPTY_OR_1(CONFIG_C) // 0

In other words, they are for testing simply flags.  Valid input is either 0 or
1, or a macro expansion that results in 0 or 1 or nothing.  Nothing else is even
supposed to work.  But, as I said above, these are not library interfaces.  You
can use them, but make sure that you use them correctly.

Regarding emptiness detection in general, it can't be done without well-defined
semantics for token-pasting arbitrary tokens (i.e. where the result is not a
single valid preprocessing token).  With variadics and placemarkers (i.e. C99
facilities) you can get awfully close--the contraint is that you cannot have a
function-like macro name as the end of the input--but that is as close as you
can get.

Regards,
Paul Mensonides

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: problem with BOOST_PP_IS_EMPTY macro

Serguei Kolos
Thank you for the explanation.

Paul Mensonides wrote:
>  
>>
>>Using the BOOST_PP_IS_EMPTY macro with string literal as
>>parameter causes compiler warning:
>>warning: pasting "BOOST_PP_IS_EMPTY_DEF_" and ""AA"" does not
>>give a valid preprocessing token
>
>
> That macro is 1) not a library interface (so why are you using it?)

I'm using it because I was looking for something to detect emptiness
and have found a macro in the preprocessor library. I can tell you what
makes me thinking that this is a public macro - it's name, which follows
the same convention as all the other macros' names in the library.


and 2) is
> not a general purpose emptiness detector (there is no such thing).  There are
> very specific constraints on what the input is supposed to be.
Now I understood that my impression was wrong.
May be it makes sense to have different prefix for private macros?

Cheers,
Sergei

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: problem with BOOST_PP_IS_EMPTY macro

Paul Mensonides
> -----Original Message-----
> From: [hidden email]
> [mailto:[hidden email]] On Behalf Of Serguei KOLOS

> > That macro is 1) not a library interface (so why are you using it?)
>
> I'm using it because I was looking for something to detect
> emptiness and have found a macro in the preprocessor library.
> I can tell you what makes me thinking that this is a public
> macro - it's name, which follows the same convention as all
> the other macros' names in the library.
>
>
> and 2) is
> > not a general purpose emptiness detector (there is no such thing).  
> > There are very specific constraints on what the input is
> supposed to be.
> Now I understood that my impression was wrong.

I believe that I originally intended those to be client interfaces.  I added
them because someone wanted them, but I didn't document them (presumably because
they aren't that useful or general).

With variadics, about the best you can do is in this regard is placing a
constraint on the input that requires the input not to end in a function-like
macro name.  Chaos (when variadics are enabled) has a IS_EMPTY_NON_FUNCTION
macro which provides general purpose emptiness detection except for that input
constraint.

Without variadics (and placemarkers), the input has such severe constraints as
to make any such macro non-general purpose.  I.e. it is highly specific to the
types of input that you need to use it with.

For now, C++ doesn't have variadics and placemarkers, so I can't add the first
one to the Boost Preprocessor library.  The second is not general purpose enough
to be added.  I wish that I could add something like this, but without variadics
and placemarkers, the result is always severely crippled.  (Trust me, I've tried
all sorts of ways to do this from all sorts of angles.  It cannot be done
without severely restricting input.)  With variadics, the result is only
slightly crippled (i.e. it is still generally usable).

> May be it makes sense to have different prefix for private macros?

Hmm.  In Chaos, I use the CHAOS_PP_ prefix for interface macros and the
CHAOS_IP_ prefix for implementation macros.  However, there are really three
types of macros--client (external) interface macros, internal interface macros,
and implementation macros.  I use CHAOS_PP_ for both external and internal
interfaces.

In Boost, any given library is (by convention) given a namespace and a macro
prefix.  E.g. for some library xyz, you'd get boost::xyz and BOOST_XYZ_.  The
BOOST_PREPROCESSOR_ prefix was shortened to BOOST_PP_ (by consensus).  So, what
I'd have to do, without special dispensation to break the convention, is use a
secondary prefix (such as BOOST_PP_IMPL_).

Regards,
Paul Mensonides

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: problem with BOOST_PP_IS_EMPTY macro

AlisdairM
Paul Mensonides wrote:

> For now, C++ doesn't have variadics and placemarkers, so I can't add
> the first one to the Boost Preprocessor library.

I believe they are present in the current working draught for C++0x
though, so you could add 'experimental' support with a C++0x feature
detection macro, if you were feeling adventurous ;?)

--
AlisdairM

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: problem with BOOST_PP_IS_EMPTY macro

Paul Mensonides
> -----Original Message-----
> From: [hidden email]
> [mailto:[hidden email]] On Behalf Of AlisdairM

> Paul Mensonides wrote:
>
> > For now, C++ doesn't have variadics and placemarkers, so I
> can't add
> > the first one to the Boost Preprocessor library.
>
> I believe they are present in the current working draught for
> C++0x though, so you could add 'experimental' support with a
> C++0x feature detection macro, if you were feeling adventurous ;?)

Well, such a thing would could be categorized as a "technological preview".  If
I was going to do that, I'd add Chaos to Boost--though I don't know if Boost is
even interested in that (and even if it is, there are several policy issues that
would have to be addressed).

Regarding future variadic support in the pp-lib...  There are a lot of things
that have to change to do this correctly--most of them involve changing argument
orders to best take advantage of variadics (and that is a significant change).

Regarding emptiness detection...  This is how Chaos does it (in case anyone is
interested)...

#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__

#define IIF(bit) PRIMITIVE_CAT(IIF_, bit)
  #define IIF_0(t, ...) __VA_ARGS__
  #define IIF_1(t, ...) t

#define SPLIT(i, ...) PRIMITIVE_CAT(SPLIT_, i)(__VA_ARGS__)
  #define SPLIT_0(a, ...) a
  #define SPLIT_1(a, ...) __VA_ARGS__

#define IS_VARIADIC(...) \
    SPLIT(0, CAT(IS_VARIADIC_R_, IS_VARIADIC_C __VA_ARGS__)) \
    /**/
  #define IS_VARIADIC_C(...) 1
  #define IS_VARIADIC_R_1 1,
  #define IS_VARIADIC_R_IS_VARIADIC_C 0,

#define IS_EMPTY_NON_FUNCTION(...) \
    IIF(IS_VARIADIC(__VA_ARGS__))( \
        0, \
        IS_VARIADIC(IS_EMPTY_NON_FUNCTION_C __VA_ARGS__ ()) \
    ) \
    /**/
  #define IS_EMPTY_NON_FUNCTION_C() ()

This will detect all emptiness except that it will fail if the input ends with a
function-like macro name, such as:

#define A() 123

IS_VARIADIC(A)

This sort of thing will either error, or yield unpredictable results.

Regards,
Paul Mensonides

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost