www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - HACK: Function to copy stack delegates

reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
LIMITATIONS:
1) It currently only copies 'void delegate()'.  Adapt it, or write a 
template, for other types.
2) This will happily copy auto objects, which must not be copied
3) This doesn't know the real size to copy, so it copies 4K.  For most 
cases, that will be more than enough, but in some functions it might not 
be enough
4) Don't call this on a heap delegate, on a class delegate, or on a 
delegate passed to you by some other function.  Only call it right when 
you declare a stack delegate, as below.

SUGGESTED USE:
void delegate() Foo(int a) {
   return copyDelegate(void delegate() { ... });
}



CODE:

union foo {
   void delegate() del;
   struct {
     char *obj;
     void function() func;
   }
};
 

void delegate() copyDelegate(in void delegate() copy) {
   const uint COPY_SIZE = 4*1024;
 

   foo temp;
   temp.del = copy;
 

   /* Since (in i386) the stack counts down, the address of temp (a local
    * variable in this stack frame) should be less than whatever stack
    * pointer the delegate uses. */
   assert(temp.obj > cast(char*)&temp);
 

   /* 1) Take the address of temp
    * 2) Cast it to a char*
    * 3) Cast it to an array of size COPY_SIZE
    * 4) Duplicate the array */
   char *buf = (cast(char*)&temp)[0..COPY_SIZE].dup;
 

   /* The current temp.obj points to some location which is a certain
    * number of bytes from the current location of temp.  Since we copied
    * a buffer where the start of the buffer is the current location of
    * temp, the new temp.obj should be the same number of bytes from the
    * start of the new buffer. */
   temp.obj = buf + (temp.obj - cast(char*)&temp);
 

   /* We've done our job, and can return now.  The new delegate has the
    * same function pointer but the object pointer now points into the
    * heap. */
   return temp.del;
}
Jun 10 2004
parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
USE 1a: REDUCE NUMBER OF ARGUMENTS IN A DELEGATE

int delegate(int,int,int)
   FillIn2Args(int delegate(int,int,int,int,int) d,
               int arg1,int arg2) {
     return copyDelegate(int delegate(int a,int b,int c)
       { return d(arg1,arg2,a,b,c); });
}

USE 1b: PRE-FILL ARGUMENTS TO A CLASS DELEGATE

int delegate(int) GetThing() {
   MyClass c = <whatever>;
   return copyDelegate(int delegate(int a)
     { return c.Function(1,2,3,a); })
}

USE 2: IMPLEMENT LAZY STREAMS

int delegate() Counter(int start,int increment) {
   int cur = start;
   return copyDelegate(int delegate()
     {
       int ret = cur;
       cur += increment;
       return ret;
     });
}

USE 3: IMPLEMENT COOPERATIVE MULTITHREADING

bool delegate() CreateThreadX() {
   int threadVariable1;
   int threadVariable2;
   int threadVariable3;

   bool delegate() nextStep;

   nextStep = &FirstStep;

   bool FirstStep() {
     <doFirstStep>;
     nextStep = &SecondStep;
     return 0;
   }
   bool SecondStep() {
     <doSecondStep>;
     if(<test>)
       nextStep = &SecondStep;
     else
       nextStep = &ThirdStep;
     return 0;
   }
   bool ThirdStep() {
     <doThirdStep>;
     nextStep = null;
     return 1;
   }

   return copyDelegate(bool delegate() {
       return nextStep();
     });
}

void ThreadRunner(bool delegate() thread1,bool delegate() thread2) {
   bool run1 = true;
   bool run2 = true;
   while(run1 && run2 ) {
     run1 = thread1();
     run2 = thread2();
   }
   while(run1)
     run1 = thread1();
   while(run2)
     run2 = thread2();
   return;
}

ThreadRunner(CreateThreadX(), CreateThreadX());
Jun 10 2004