www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Questions about opAssign alternate and template quality

reply nobody <nobody mailinator.com> writes:
I wanted to try out D's template system so I decided to define data structures 
that represent all the permutations of RGB, HLS, RGBA and HLSA. I decided to 
convert between the various types by overriding opAssign under the mistaken 
impression that D supported it. Impressive when you do the math:

     3! + 3! + 4! + 4! = 60 types
    (3! + 3! + 4! + 4!)^2 = 3600 opAssigns

So my first question is whether anyone has an elegant alternative to using
opAssign?

My second question is mostly an open invitation to make suggestions for 
improving my template writing style. In particular I am suspicious that there
is 
a way to take better advantage of templates and not write out all 60
permutations.

So here is the actual code. I only included the RGB permutations to keep it as 
short as possible.


union PixArray
{
   PixBGR[] bgr;
   PixBRG[] brg;
   PixGBR[] gbr;
   PixGRB[] grb;
   PixRBG[] rbg;
   PixRGB[] rgb;
}


template PixBGR_Perms_opAssignBGR(T,U)
{

   T opAssign(U that)
   {
     ubyte tempB = that.b;
     ubyte tempG = that.g;
     ubyte tempR = that.r;
     this.b = tempB;
     this.g = tempG;
     this.r = tempR;
     return *this;
   }

}


template PixBGR_Perms(T)
{
   alias b blue;
   alias g green;
   alias r red;

   // opAssign defined for all perms
   mixin PixBGR_Perms_opAssignBGR!(T,PixBGR);
   mixin PixBGR_Perms_opAssignBGR!(T,PixBRG);
   mixin PixBGR_Perms_opAssignBGR!(T,PixGBR);
   mixin PixBGR_Perms_opAssignBGR!(T,PixGRB);
   mixin PixBGR_Perms_opAssignBGR!(T,PixRBG);
   mixin PixBGR_Perms_opAssignBGR!(T,PixRGB);
}


align(1)
{
   struct PixBGR { ubyte b; ubyte g; ubyte r; mixin PixBGR_Perms!(PixBGR); }
   struct PixBRG { ubyte b; ubyte r; ubyte g; mixin PixBGR_Perms!(PixBRG); }
   struct PixGBR { ubyte g; ubyte b; ubyte r; mixin PixBGR_Perms!(PixGBR); }
   struct PixGRB { ubyte g; ubyte r; ubyte b; mixin PixBGR_Perms!(PixGRB); }
   struct PixRBG { ubyte r; ubyte b; ubyte g; mixin PixBGR_Perms!(PixRBG); }
   struct PixRGB { ubyte r; ubyte g; ubyte b; mixin PixBGR_Perms!(PixRGB); }
}
Aug 10 2006
parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
nobody wrote:
 I wanted to try out D's template system so I decided to define data 
 structures that represent all the permutations of RGB, HLS, RGBA and 
 HLSA. I decided to convert between the various types by overriding 
 opAssign under the mistaken impression that D supported it. Impressive 
 when you do the math:
 
     3! + 3! + 4! + 4! = 60 types
    (3! + 3! + 4! + 4!)^2 = 3600 opAssigns
 
 So my first question is whether anyone has an elegant alternative to 
 using opAssign?

I don't know of any elegant alternative. I also find it very unfortunate that opAssign isn't overloadable for structs.
 My second question is mostly an open invitation to make suggestions for 
 improving my template writing style. In particular I am suspicious that 
 there is a way to take better advantage of templates and not write out 
 all 60 permutations.
 
 So here is the actual code. I only included the RGB permutations to keep 
 it as short as possible.

Implicit function template instantiation and some static ifs can help you. Unfortunately, IFTI isn't yet implemented for member functions, but you can make a free function like: void pixAssign(A,B)(out A A, in B b) { static if (is(a.a) && is(b.a)) { // Alpha a.a = b.a; } else static if(is(a.a)) { a.a = typeof(a.a).max; } static if (is(a.r) && is(b.r)) { // RGB->RGB auto r = b.r; auto g = b.g; auto b = b.b; a.r = r; a.g = g; a.b = b; } else static if (is(a.h) && is(b.h)) { // HLS -> HLS auto h = b.h; auto l = b.l; auto s = b.s; a.h = h; a.l = l; a.s = s; } else static if(is(a.r)) { // HLS -> RGB assert(0,"not implemented."); } else static if(is(b.r)) { // RGB -> HLS assert(0,"not implemented."); } } Which should take care of all 3600 combinations of opAssign. is(x.y) is there just to check for the existence of a field y in x. Which can be called: pixAssign(dst,src); You can also add the following to your PixColor structs: void opAssign(B)(B b) { pixAssign(*this,b); } Bur, until IFTI is implemented for member functions, you would have to call it: c1.opAssign!(typeof(c2))(c2); And one can always hope, that in the future it will be: c1 = c2;
 align(1)
 {
   struct PixBGR { ubyte b; ubyte g; ubyte r; mixin PixBGR_Perms!(PixBGR); }
   struct PixBRG { ubyte b; ubyte r; ubyte g; mixin PixBGR_Perms!(PixBRG); }
   struct PixGBR { ubyte g; ubyte b; ubyte r; mixin PixBGR_Perms!(PixGBR); }
   struct PixGRB { ubyte g; ubyte r; ubyte b; mixin PixBGR_Perms!(PixGRB); }
   struct PixRBG { ubyte r; ubyte b; ubyte g; mixin PixBGR_Perms!(PixRBG); }
   struct PixRGB { ubyte r; ubyte g; ubyte b; mixin PixBGR_Perms!(PixRGB); }
 }

You can also make a template that automatically defines your Pix??? types, but I am not sure it is worth it. alias Pix!(R,G,B) PixRGB; alias Pix!(R,G,B,A) PixRGBA; alias Pix!(A,R,G,B) PixARGB; alias Pix!(H,L,S) PixHLS; alias Pix!(B,G,R) PixBGR; alias Pix!(R,B,G) PixRBG; alias Pix!(B,R,G) PixBRG; ... /Oskar
Aug 10 2006
parent nobody <nobody mailinator.com> writes:
Oskar Linde wrote:

 My second question is mostly an open invitation to make suggestions 
 for improving my template writing style. In particular I am suspicious 
 that there is a way to take better advantage of templates and not 
 write out all 60 permutations.

 So here is the actual code. I only included the RGB permutations to 
 keep it as short as possible.

Implicit function template instantiation and some static ifs can help you. Unfortunately, IFTI isn't yet implemented for member functions, but you can make a free function like: void pixAssign(A,B)(out A A, in B b) { static if (is(a.a) && is(b.a)) { // Alpha a.a = b.a; } else static if(is(a.a)) { a.a = typeof(a.a).max; } static if (is(a.r) && is(b.r)) { // RGB->RGB auto r = b.r; auto g = b.g; auto b = b.b; a.r = r; a.g = g; a.b = b; } else static if (is(a.h) && is(b.h)) { // HLS -> HLS auto h = b.h; auto l = b.l; auto s = b.s; a.h = h; a.l = l; a.s = s; } else static if(is(a.r)) { // HLS -> RGB assert(0,"not implemented."); } else static if(is(b.r)) { // RGB -> HLS assert(0,"not implemented."); } } Which should take care of all 3600 combinations of opAssign. is(x.y) is there just to check for the existence of a field y in x.

Thanks for the great post! Your pixAssign function is a great example and helped me better understand static if, is and auto. It might take awhile before I can see why there would be trouble with trying to use a mixin to avoid paramatized calls to opAssign.
Aug 11 2006