Is there a way to return an lvalue and also an rvalue from the same member function?

realhet real_het at hotmail.com
Sun Sep 20 15:52:49 UTC 2020


On Sunday, 20 September 2020 at 14:54:09 UTC, Steven 
Schveighoffer wrote:
> On 9/20/20 9:30 AM, realhet wrote:
>ref inout(int) x() inout { return array[0]; }

This doesn't work when I type:
v.x++;

I want to make a similar type like the GLSL vectors. Where the 
following thing is valid:
vec4 a, b;
a.yzw = b.xzy;

On the left there is a contiguous area of the vector a. It just 
starts form the 1th element, not form the 0th: a[1..4].  It could 
be work as an lvalue.

On the right there is a non-contiguous swizzle: [b.x, b.z, b.y]. 
But because it is 3 element wide, it can be assigned to the 
lvalue "a.yzw". This value cannot be an lvalue because the order 
of the elements are not the same as in memory. So it must 
returned as a const.

Here's what I achieved so far:

private enum swizzleRegs = ["xyzw", "rgba", "stpq"]; //vector, 
color, and texture component letters

struct Vec(CT, int N)
if(N>=2 && N<=4){
   alias VectorType = typeof(this);
   alias ComponentType = CT;
   enum VectorTypeName = ComponentTypePrefix ~ "vec" ~ N.text;

   CT[N] array = [0].replicate(N).array; //default is 0,0,0, not 
NaN.  Just like in GLSL.
   alias array this;
   enum length = N;

   ...

   static foreach(regs; swizzleRegs)
     static foreach(len; 1..N+1)
       static foreach(i; 0..N-len+1)
         static if(len==1){
1)        mixin(format!"auto %s() const { return array[%s]; 
}"(regs[i], i));
2)        mixin(format!"ref  %s()       { return array[%s]; 
}"(regs[i], i));
         }else{
3)        mixin(format!"auto %s() const { return Vec!(CT, 
%s)(array[%s..%s]); }"(regs[i..i+len], len, i, i+len));
4)        mixin(format!"ref  %s()       { return *(cast(Vec!(CT, 
%s)*) (array[%s..%s])); }"(regs[i..i+len], len, i, i+len));
         }

}

So what I feel, the mixin()-s are a bit nasty :D But sufficient 
for the following two criteria:

1.  immutable vec3 a; a.xy.writeln; // displays a const vec2 
casting a constant memory lovation to vec2  -> 3)

2.  vec3 b;  b.g++;  // accessing the 2. component(g=green, 
1based) of a vec3 with a memory reference because it is mutable.

I only want lvalues from swizzle combinations that are adjacent 
in memory, so I can cast them. For all the rest I'm using 
opDispatch(string def)() with a strict constraint on the string 
'def'.

For example: a.xxxx returns vec4(a.x, a.x, a.x, a.x);
a.x01z returns vec4(a.x, a.0, a.1, a.z);

The only thing I don't want  to implement from the GLSL spec is 
those non-contigous swizzle assignments like:
a.zyx = vec3(1,2,3) ***
but
a.xyz = vec3(1,2,3) should work.

*** maybe with a struct that refers to the original vector and 
the swizzle code it could be also possible. :D


More information about the Digitalmars-d-learn mailing list