#ifndef __generator_h_
#define __generator_h_
#include <boost/preprocessor/cat.hpp>
struct _generator
{
void * _addr;
_generator():_addr(0) {}
};
//------------------------------------------------------------------------------
#define $generator(NAME) class NAME : protected _generator
//.......
/// \note NB: Remember! The values of local varaibles are not preserved between
/// generator() invocation. Use them with precaution or use class members.
#define $emit(T) bool operator()(T& _rv) \
{ \
GOTO_GENERATOR_LABEL \
{
//.......
#define $yield(V) do { \
_rv = (V); \
SAVE_ADDR; \
return true; \
GENERATOR_LABEL:; \
} while (0);
//.......
#define $stop } \
_addr = 0; \
return false; \
}
//------------------------------------------------------------------------------
/// auxiliary macroses
#define GENERATOR_LABEL BOOST_PP_CAT(generator_label_,__LINE__)
#if defined(_MSC_VER)
# define GOTO_GENERATOR_LABEL \
if ( _addr ) \
{ \
void * addr = _addr; \
__asm \
{ \
__asm jmp addr \
} \
}
# define SAVE_ADDR \
{ \
void * pAddr = &_addr; \
__asm \
{ \
__asm mov ebx, dword ptr [pAddr] \
__asm mov eax, OFFSET GENERATOR_LABEL \
__asm mov dword ptr [ebx], eax \
} \
}
#elif defined(__GNUC__)
# define GOTO_GENERATOR_LABEL \
if ( _addr ) \
{ \
void * addr = _addr; \
goto *addr; \
}
# define SAVE_ADDR \
{ \
void * addr = &&GENERATOR_LABEL; \
_addr = addr; \
}
#else
# error You have to check a support of "goto *label" on your platform or implement it yourself.
#endif
#endif // __generator_h_
//=============================================================================
#include <stdio.h>
$generator(desc)
{
int m_i;
public:
desc( int start=-1 ) : m_i(start) {}
$emit(int)
{
for(; m_i >= 0; --m_i)
{
switch ( m_i )
{
case 9 : case 7 :
$yield( m_i + 100 );
break;
case 5:
$yield( m_i + 100000 );
break;
default:
$yield( m_i );
}
$yield( m_i );
}
}
$stop
};
int main(int argc, char* argv[])
{
desc gen( 11 );
int i;
while(gen(i))
{
printf("got number %d\n", i);
}
} |