Benjamin Goldberg <[EMAIL PROTECTED]> wrote:
> Actually, I think the following interface would be better:

>    void freeze(PMC *freezer);
>    void thaw  (PMC *thawer);

I'm thinking of (in horrible pseudo code ;-):

    typedef struct {
        size_t action_func_nr; // clone, freeze, thaw, dump vtable#
        PMC *todo_list_fifo;
        PMC *seen;
        size_t id;
        UINTVAL flags;
        PMC *other;     // for clone and thaw
        void *result;   // freeze, dump append string here
        void *other_things_needed;
    } Traverse_info;


    INTVAL traverse(Traverse_info *info) {
        (SELF->vtable[info->action_func_nr]) (INTERP, SELF, info);
        foreach item (SELF.elements) {
            if (item->needs_cloning)
                VTABLE_push(INTERP, info->todo_list, item);
            else
                ;// copy native type
        }
        return 0; // ok
    }


    INTVAL clone(Traverse_info *info) {
        if (SELF.can("clone"))  // overridden?
            return SELF.invoke(SELF.find_method("clone"), info);
        if (info->flags & DO_CLONE)
            copy(info->other->state, SELF.state);
        else
            ; // other pointer already done for self-ref aggregates
        return 0; // ok
    }

freeze_thaw_clone_dump.c // ;-)

    do_clone(PMC *pmc) {
       return (PMC*)
       do_traverse(action_func_nr = (VTABLE.clone-VTABLE[0], CLONE, pmc);
    }

    void *do_traverse(func, what, pmc) {
       info.action_func_nr = func;
       info.todo_list_fifo = new Fifo;
       info.flags = what;
       info.seen = new Hash;
       info.result = NULL;
       push(info.todo_list, pmc);
       while (info.todo_list_fifo.elements()) {
           todo = shift info.todo_list_fifo;
           if (seen{todo})
                // set flags
                info.flags = DO_NOT_CLONE;
                info.other = todo;
           else {
               seen{todo} = ++ID;
               switch (what) {
                 case CLONE:
                 info.other = new todo.type();
                 if (!info.result)
                     info.result = info.other; // top clone
                 break;
                 ...
               }
           }
           info.id = ID;
           if (todo->vtable->traverse(...,&info))
              ; // error
       }
       return (void*) info->result;
    }

[ big snip ]

Above functionality does IMHO match your description. The only
difference is, that I'd like to use that not only for freeze/thaw, but
for clone and dump too.

The thaw part is still missing in above pseudocode. It needs an
additional ID-array for lookup + some more things. Its better done in a
separate subroutine.

There is one more indirection through the passed in vtable but that
doesn't matter very much. Constructing new PMCs or STRINGs takes much
more time.

And I'd like to have a vtable->dump too. Dan's approach of first
freezing the PMC and then let the debugger construct the dump doesn't
work IMHO: we already have dynamic loaded PMC classes. The debugger
doesn't know anything about such classes, so these classes have to
provide this functionality themselfs. We could rename dump() to
pretty_print() though.

leo

Reply via email to