M
Marcos Stefanakopolus
In C# is there any way to use the concept of delegates to have multiple implementations of a particular block of code, so that you can choose between them without the overhead of possibly expensive if() or switch() logic, and without the overhead of a function call?
As an example, consider the task of resizing a bitmap from size X1,Y1 to size X2,Y2 (may be shrunk or expanded, may or may not maintain aspect ratio). Code that handles the general case looks like this:
Bitmap In = new Bitmap(...constructed from a file, let's say),
Out = new Bitmap(X2,Y2);
// BoxW and BoxH represent the size of the patch in the input image that each
// output pixel corresponds to.
int BoxW, BoxH;
BoxW = (Out.Width >= In.Width) ? 1 : (int)((double)In.Width / (double)Out.Width);
BoxH = (Out.Height >= In.Height) ? 1 : (int)((double)In.Height / (double)Out.Height);
double XFactor = (double)In.Width / (double)Out.Width,
YFactor = (double)In.Height / (double)Out.Height;
double R, G, B, // Sums for the color channels.
BoxArea; // not pre-computed because near the edges it may not == BoxW*BoxH.
Color C;
// loop over pixels in the output image,
for(int x = 0; x < Out.Width; x++)
for(int y = 0; y < Out.Height; y++)
{
R = G = B = BoxArea = 0.0;
// sum the R,G,B values of all input pixels in the box
for(int j = 0; j < BoxW; j++)
for(int k = 0; k < BoxH; k++)
if((int)((double)x*XFactor)+j < In.Width &&
(int)((double)y*YFactor)+k < In.Height)
{
C = In.GetPixel((int)((double)x*XFactor)+j,
(int)((double)y*YFactor)+k);
R += (double)(C.R);
G += (double)(C.G);
B += (double)(C.B);
BoxArea++;
}
// set output pixel to average of pixels in the box.
Out.SetPixel(x,y,Color.FromArgb((int)(R / BoxArea),(int)(G / BoxArea),(int)(B / BoxArea)));
}
This works just dandy, but if the output image is bigger than the input image, then BoxW == BoxH == 1, meaning that the above code in that case reduces to:
for(int x = 0; x < Out.Width; x++)
for(int y = 0; y < Out.Height; y++)
{
Out.SetPixel(x,y,In.GetPixel((int)((double)x*XFactor)+j,
(int)((double)y*YFactor)+k));
}
This, clearly, would be much faster. I don't want to do this...
for(int x = 0; x < Out.Width; x++)
for(int y = 0; y < Out.Height; y++)
if(BoxW == BoxH == 1) {
// fast case code
} else {
// general case code
}
....because it's silly to have to evaluate the conditional every time through the inner loop; BoxW and BoxH are loop invariants! I could use delegates to package up the fast case and the general case into separate functions, but then I'm penalized by the overhead of a function call. Is there some way to use delegates in the context of anonymous blocks of code so I could say something like:
// setup:
anonymous_block_delegate_type D;
....
if(BoxW == BoxH == 1) {
D = { Out.SetPixel(x,y,In.GetPixel((int)((double)x*XFactor)+j,
(int)((double)y*YFactor)+k)); }
} else {
D = { // general purpose code }
}
....
for(int x = 0; x < Out.Width; x++)
for(int y = 0; y < Out.Height; y++)
magic_D_invoking_syntax;
That way I could have my cake and eat it too, as it were. Any hope here?
As an example, consider the task of resizing a bitmap from size X1,Y1 to size X2,Y2 (may be shrunk or expanded, may or may not maintain aspect ratio). Code that handles the general case looks like this:
Bitmap In = new Bitmap(...constructed from a file, let's say),
Out = new Bitmap(X2,Y2);
// BoxW and BoxH represent the size of the patch in the input image that each
// output pixel corresponds to.
int BoxW, BoxH;
BoxW = (Out.Width >= In.Width) ? 1 : (int)((double)In.Width / (double)Out.Width);
BoxH = (Out.Height >= In.Height) ? 1 : (int)((double)In.Height / (double)Out.Height);
double XFactor = (double)In.Width / (double)Out.Width,
YFactor = (double)In.Height / (double)Out.Height;
double R, G, B, // Sums for the color channels.
BoxArea; // not pre-computed because near the edges it may not == BoxW*BoxH.
Color C;
// loop over pixels in the output image,
for(int x = 0; x < Out.Width; x++)
for(int y = 0; y < Out.Height; y++)
{
R = G = B = BoxArea = 0.0;
// sum the R,G,B values of all input pixels in the box
for(int j = 0; j < BoxW; j++)
for(int k = 0; k < BoxH; k++)
if((int)((double)x*XFactor)+j < In.Width &&
(int)((double)y*YFactor)+k < In.Height)
{
C = In.GetPixel((int)((double)x*XFactor)+j,
(int)((double)y*YFactor)+k);
R += (double)(C.R);
G += (double)(C.G);
B += (double)(C.B);
BoxArea++;
}
// set output pixel to average of pixels in the box.
Out.SetPixel(x,y,Color.FromArgb((int)(R / BoxArea),(int)(G / BoxArea),(int)(B / BoxArea)));
}
This works just dandy, but if the output image is bigger than the input image, then BoxW == BoxH == 1, meaning that the above code in that case reduces to:
for(int x = 0; x < Out.Width; x++)
for(int y = 0; y < Out.Height; y++)
{
Out.SetPixel(x,y,In.GetPixel((int)((double)x*XFactor)+j,
(int)((double)y*YFactor)+k));
}
This, clearly, would be much faster. I don't want to do this...
for(int x = 0; x < Out.Width; x++)
for(int y = 0; y < Out.Height; y++)
if(BoxW == BoxH == 1) {
// fast case code
} else {
// general case code
}
....because it's silly to have to evaluate the conditional every time through the inner loop; BoxW and BoxH are loop invariants! I could use delegates to package up the fast case and the general case into separate functions, but then I'm penalized by the overhead of a function call. Is there some way to use delegates in the context of anonymous blocks of code so I could say something like:
// setup:
anonymous_block_delegate_type D;
....
if(BoxW == BoxH == 1) {
D = { Out.SetPixel(x,y,In.GetPixel((int)((double)x*XFactor)+j,
(int)((double)y*YFactor)+k)); }
} else {
D = { // general purpose code }
}
....
for(int x = 0; x < Out.Width; x++)
for(int y = 0; y < Out.Height; y++)
magic_D_invoking_syntax;
That way I could have my cake and eat it too, as it were. Any hope here?