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*:
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:
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:
Thank you all...
SDB@79