Exercise at end of Ch. 56 of "Programming in D"

Salih Dincer salihdb at hotmail.com
Mon Aug 22 01:03:04 UTC 2022


On Saturday, 20 August 2022 at 21:26:25 UTC, Paul Backus wrote:
>
> Fortunately there is no need to invent our own hash function 
> here, because we can use the generic hashOf [1] from druntime:
>
>     override size_t toHash() const {
>         return hashOf(y, hashOf(x));
>     }
>
> The second argument is optional, and is used when you want to 
> "accumulate" a single hash value from multiple input values.
>
> [1] https://druntime.dpldocs.info/object.hashOf.1.html

It's very simple and beautiful, thanks!

I know, off-topic but valuable info; we can gain a nice 
auto-constructor template*:

```d
enum defaultClassConstructor = q{
   this(typeof(this.tupleof) params) {
     static foreach (i; 0..this.tupleof.length)
       this.tupleof[i] = params[i];
   }
};

struct Color {
   ubyte r, g, b, a;
}

class Point {
   Color c;
   int x, y;
   bool h;

   mixin(defaultClassConstructor);
}

unittest
{
   Color foo = { r : 0x30,
                 g : 0xd5,
                 b : 0xc8
   };

   auto bar = new Point(foo, 320, 240, true);

   assert(bar.h);
   assert(bar.x == 320);
   assert(bar.y == 240);
   assert(bar.c.a == 0);
   assert(bar.c.r == 48);
   assert(bar.c.g == 213);
   assert(bar.c.b == 200);
}
```

(*) I learned on this forum (from Steven Schweighoffer, I think):

Or so this is also very good:

```d
void main()
{
   auto colorWithAlpha = vec4i(100, 150, 200, 300);
        colorWithAlpha.r = 120;
   assert(colorWithAlpha.r == 120);
   assert(colorWithAlpha.g == 150);
   assert(colorWithAlpha.b == 200);
   assert(colorWithAlpha.a == 300);

   auto point3D = vec3i(100, 200, 300);
        point3D.z /= 2;
   assert(point3D.x == 100);
   assert(point3D.y == 200);
   assert(point3D.z == 150);

   auto point2D = vec2i(100, 200);
        point2D.y = point3D.z;
   assert(point2D.x == 100);
   assert(point2D.y == 150);
}

template vec2(T) { alias Vector!(T, 2) vec2; }
alias vec2!int    vec2i;
alias vec2!float  vec2f;
alias vec2!double vec2d;

template vec3(T) { alias Vector!(T, 3) vec3; }
alias vec3!int    vec3i;
alias vec3!float  vec3f;
alias vec3!double vec3d;

template vec4(T) { alias Vector!(T, 4) vec4; }
alias vec4!int    vec4i;
alias vec4!float  vec4f;
alias vec4!double vec4d;

enum isVector(T) = is(T : Vector!A, A...);

struct Vector(T, int N)
{
   static assert(N >= 1);
   import std.conv,
          std.format,
          std.traits;

   union
   {
     T[N] v;
     struct
     {
       static if(N >= 1)
       {
         T x; alias x r;
       }
       static if(N >= 2)
       {
         T y; alias y g;
       }
       static if(N >= 3)
       {
         T z; alias z b;
       }
       static if(N >= 4)
       {
         T w; alias w a;
       }
     }
   }

   this(Args...)(Args args)
   {
     static if (args.length == 1)
     {// Construct a Vector from a single value.
       opAssign!(Args[0])(args[0]);
     }
     else
     { // validate the total argument count across scalars and 
vectors
       template argCount(T...)
       {
         static if(T.length == 0)
           enum argCount = 0; // done recursing
         else static if(isVector!(T[0]))
           enum argCount = T[0]._N + argCount!(T[1..$]);
         else
           enum argCount = 1 + argCount!(T[1..$]);
         }

         static assert(argCount!Args <= N, "Too many arguments in 
vector constructor");

         int index = 0;
         foreach(arg; args)
         {
           static if(isAssignable!(T, typeof(arg)))
           {
             v[index] = arg;
             index++; // has to be on its own line (DMD 2.068)
           }
           else static if (isVector!(typeof(arg)) && 
isAssignable!(T, arg._T))
           {
             mixin(generateLoopCode!("v[index + @] = arg[@];", 
arg._N)());
             index += arg._N;
           }
           else static assert(false, "Unrecognized argument in 
Vector constructor");
         }
         assert(index == N, "Bad arguments in Vector constructor");
       }
   }

   /// Assign a Vector with a static array type.
   ref Vector opAssign(U)(U arr)
   if ((isStaticArray!(U) && isAssignable!(T, typeof(arr[0])) && 
(arr.length == N)))
   {
     mixin(generateLoopCode!("v[@] = arr[@];", N)());
     return this;
   }

   /// Assign with a dynamic array.
   /// Size is checked in debug-mode.
   ref Vector opAssign(U)(U arr)
   if (isDynamicArray!(U) && isAssignable!(T, typeof(arr[0])))
   {
     assert(arr.length == N);
     mixin(generateLoopCode!("v[@] = arr[@];", N)());
     return this;
   }

   /// Assign from a samey Vector.
   ref Vector opAssign(U)(U u)
   if (is(U : Vector))
   {
     v[] = u.v[];
     return this;
   }

   /// Assign from other vectors types (same size, compatible 
type).
   ref Vector opAssign(U)(U x)
   if(isVector!U && isAssignable!(T, U._T)
                 && (!is(U: Vector))
                 && (U._N == _N)
      ) {
     mixin(generateLoopCode!("v[@] = x.v[@];", N)());
     return this;
   }

   /// Returns: a pointer to content.
   inout(T)* ptr() inout @property
   {
     return v.ptr;
   }

   /// Converts to a pretty string.
   string toString() const nothrow
   {
     try
       return format("%s", v);
     catch (Exception e)
       assert(false); // should not happen since format is right
   }

   private
   {
     enum _N = N;
     alias T _T;

     // define types that can be converted to this, but are not 
the same type
     template isConvertible(T)
     {
       enum bool isConvertible =
          (!is(T : Vector)) &&
            is(typeof( { T x_Detect;
                         Vector v = x_Detect;
                       }()
                     )
              );
     }

     static
     string generateLoopCode(string str, int N)()
     {
       import std.string;
       string result;
       for(int i; i < N; ++i)
       {
         string index = ctIntToString(i);
         // replace all @ by indices
         result ~= str.replace("@", index);
       }
       return result;
     }

     // Speed-up CTFE conversions
     static
     string ctIntToString(int n)
     {
       static
       immutable string[16] table = ["0", "1", "2",
                                     "3", "4", "5",
                                     "6", "7", "8",
                                     "9"];
       if (n < 10) return table[n];
       else return n.to!string;
     }
   } // private
}
```

A big thank you to Ali, Steve and Paul for this information I've 
gained. Again thank you to the others whose names I cannot 
mention.

**Disclaimer:** The Vector structure above is not my own code, I 
couldn't find its source. But it can belong to the following 
repositories:

* [dlangui](https://github.com/buggins/dlangui) (Vadim Lopatin)
* [dlib](https://github.com/gecko0307/dlib) (Timur Gafarov)

Thank you all...

SDB at 79



More information about the Digitalmars-d-learn mailing list