Re[23]: Generators in C++, (a.k.a. foreach & iteartors)
От: c-smile Канада http://terrainformatica.com
Дата: 30.05.08 15:38
Оценка: 34 (1)
Здравствуйте, remark, Вы писали:

CS>>В общем случае нужен stack on the heap.


CS>>Для C++ по всей видимости вполне себе будет достаточно объявления _generator как CRTP

CS>>структуры/шаблона плюс поле _generatror<NAME>* _stack.

CS>>Это точно будет работать — т.е. можно и рекурсивные вызовы делать (но только себя самого)


R>А можешь привести полную реализацию с примером использования. А то пока это всё не складывается в единое целое...


Вот generator с поддержкой restart — рекурсивный рестарт себя самого.

template<typename T>
  struct _generator
  {
    T* _stack;
    int _line;
    _generator():_stack(0), _line(-1) {}
    void _push() { T* n = new T; *n = *static_cast<T*>(this); _stack = n; }
    bool _pop() { if(!_stack) return false; T* t = _stack; *static_cast<T*>(this) = *_stack; t->_stack = 0; delete t; return true; }
    ~_generator() { while(_pop()); }
  };

  #define $generator(NAME) struct NAME : public _generator<NAME>

  #define $emit(T) bool operator()(T& _rv) { \
                      if(_line < 0) _line=0; \
                      $START: switch(_line) { case 0:;

  #define $stop  } _line = 0; if(_pop()) goto $START; return false; }

  #define $restart(WITH) { _push(); _stack->_line = __LINE__; _line=0; WITH; goto $START; case __LINE__:; }

  #define $yield(V)     \
          do {\
              _line=__LINE__;\
              _rv = (V); return true; case __LINE__:;\
          } while (0)


Используется так (обход дерева):

struct node
{
   int   value;
   node* next;
   node* kid;
   node(int v):value(v), next(0), kid(0) {}
   node* foster( node* child ) { child->next = kid; kid = child; return child; }
};

$generator(scan)
{
  node* n;
  scan( node* root = 0 ): n(root) {}

  $emit(int)
    for(;n; n = n->next)
    {
      $yield(n->value);
      if( n->kid )
        $restart( n = n->kid );
    }
  $stop
};

int main(int argc, char* argv[])
{
  node * root = new node(0);
  root->foster(new node(1));
  root->foster(new node(2));
  root->foster(new node(3));
  root->foster(new node(4));
  node * child5 = root->foster(new node(5));
  root->foster(new node(6));
  root->foster(new node(7));
  root->foster(new node(8));
  root->foster(new node(9));

  child5->foster(new node(50));
  child5->foster(new node(51));
  child5->foster(new node(52));
  child5->foster(new node(53));

  scan g(root);
  for(int n; g(n);)
      printf("n = %d\n",n);
    return 0;
}


Усовершенствования возможны.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.