template parameters
Charles Hixson
charleshixsn at earthlink.net
Thu Sep 2 21:28:23 UTC 2021
Thanks. See below for what I did.
On 8/29/21 5:05 PM, Ali Çehreli via Digitalmars-d-learn wrote:
> On 8/29/21 3:31 PM, Charles Hixson wrote:
> > Thanks. I going to have to study:
> >
> > enum supportsCall = isIntegral!(typeof(T.init.%s()));
> >
> >
> > for awhile to make any sense of that, but it looks like just what I was
> > looking for.
>
> Trying to explain with comments:
>
> // This is an eponymous template because it contains
> // a symbol that's the same as the name of this template.
> // And that symbol is 'supportsCall'. So, this template
> // will be whatever that symbol is. (In this case, it
> // will be a compile-time know entity: 'enum bool'.)
>
> template supportsCall(T, string func) {
> import std.format : format;
> import std.traits : isIntegral;
>
> // This is a string expression we will mix-in below.
> enum expr = format!q{
> enum supportsCall = isIntegral!(typeof(T.init.%s()));
> }(func);
>
> // The above expression will be the following e.g.
> // for 'int' and for "ndx":
> //
> // enum supportsCall = isIntegral!(typeof(int.init.ndx()));
> //
> // So, it's determining whether the typeof the expression
> // int.init.ndx() is an integral.
> //
> // 'supportsCall' is a bool, which I could have made explicit:
> //
> // enum bool supportsCall = [...]
> //
> // You can prove it for yourself by "printing" the expression
> // at compile time:
>
> pragma(msg, expr);
>
> // Here is where we mix-in the expression into this template's
> // definition.
>
> mixin (expr);
> }
>
> Then the whole template can be used as a compile-time bool value.
>
> Ali
>
I'm going to need to save that for the future. I ran into errors in
other sections. I suspect that a general form would require static if
tests in numerous routines. Anyway, if you're interested this is what I
ended up with. (I think it's error free, but not all paths have been
tested.)
import std.algorithm : remove;
import std.exception;
import std.stdio;
import std.traits : isIntegral;
import utils; // this is for my randomized integer code based
on time: rndT
/** An Associative Array with some Randomization and Linear features.
* Note: This is done in a simplified and not too generalized fashion
so that I don't need to
* figure out template parameters at the moment. It should be
redone later, when my mastery
* is better. The current version should work for classes and
structs that have a function
* int T.ndx() that returns a unique id. That id (called the
key) is used as an AA index
* to find the instance, with duplicates not being allowed. */
class AARL2 (T)
{ /** The associative array of cells, with the index as the key. */
T[int] aa;
/** A linear array of cell key values. This is ordered by the
order in which they were
* inserted rather than by value. */
int[] rl;
/** Create an AARL from an array of cells. The array must have
no entries with duplicate
* key values (i.e. cell.ndx). Currently this throws an
exception. Consider how it could
* be handled more gracefully. */
this (T[] inp)
{ foreach (T c; inp)
{ int key = c.ndx;
enforce (key !in aa, "Attempt to insert a key already
present.");
aa[key] = c;
rl ~= key;
}
}
this () {}
/** Access members by serial position of key. (Not the value of
the key!) */
T at (int i)
in { assert (i >= 0 && i < rl.length, "Index outside
bounds"); }
body
{ int key = rl[i];
return aa[key];
}
/** This is a read-only count of number of entries. */
long length() { return aa.length; }
bool opBinaryRight(string op)(int key) const
if (op == "in")
{ return cast (bool)(key in aa); }
bool opBinaryRight(string op)(T c) const
if (op == "in")
{ return cast (bool)(c.ndx in aa); }
/** Allow the [] operator to retrieve instances by key value. */
T opIndex(int key)
{ if (key in aa) return aa[key];
return null;
}
/** "append" an instance of T. */
void opOpAssign (string op)(T c)
// if (op == "~=" && isIntegral!(typeof(T.init.ndx())
if (op == "~")
{ append (c); }
/** "append" an instance of T.
* Note: I need a better response to an attempt to add
duplicates. */
void append (T c)
{ if (c is null)
{ stderr.writeln ("Attempt to add a null T to the AARL
rejected.");
return;
}
int key = c.ndx;
if (key in aa)
{ aa[key] = c; }
else
{ aa[key] = c;
rl ~= key;
}
return;
}
/** Pop the most recently added T off the table. */
T pop ()
{ if (rl.length < 1) return null;
T c = aa[rl[cast(int)rl.length - 1]];
aa.remove (c.ndx);
rl.length -= 1;
return c;
}
/** Pop a random cell off the table. */
T popR()
{ int which = rndT(cast(int)rl.length);
int key = rl[which];
assert (key in aa, "AARL popR Logic error..1..but where?");
T c = aa[key];
remove(c);
return c;
}
/** Pop the most recently added Cells off the table until the
key is found. No value is returned.
* Note: The key value is left in the AARL. */
void popUntil (T c)
in { assert (c.ndx in aa, "Trying to pop until a value is
reached which isn't in the table."); }
body
{ while (c.ndx != rl[rl.length - 1])
{ pop(); }
}
/** Push a cell onto the table.
* Returns: True if the push was successful. False if either
the item was null or one with
* the same key value was already in the table. */
bool push (T c)
{ if (c is null) return false;
if (c.ndx in aa) return false;
aa[c.ndx] = c;
rl ~= c.ndx;
return true;
}
/** Read the most recently pushed cell of the table.
* WARNING: No valid return value exists when the AARL is empty
and T is not a class.
* Consider throwing an exception in that case. Currently
that case is not handled. */
T read()
{ int key = rl[rl.length - 1];
assert (key in aa, "AARL read Logic error...but where?");
return aa[key];
}
/** Read a random cell of the table.
* WARNING: No valid return value exists when the AARL is empty
and T is not a class.
* Consider throwing an exception in that case. Currently
that case is not handled. */
T readR()
{ int which = rndT(cast(int)rl.length);
int key = rl[which];
assert (key in aa, "AARL readR Logic error...but where?");
return aa[key];
}
/** Remove a T from the table.
* Returns: True if successful, otherwise false. */
bool remove (T c)
{ if (c is null) return false;
return removeKey (c.ndx);
}
/** Remove the T whose key matches the given key from the table.
* Returns: True if successful, otherwise flase. */
bool removeKey (int key)
{ if (key !in aa) return false;
int i = 0;
while (i < rl.length)
{ if (rl[i] == key)
{ rl.remove(i);
aa.remove(key);
return true;
}
i++;
}
assert (false, "Logic Error: never come here");
}
}
unittest
{ class AARLTest1
{ int ndx_;
this () { ndx_ = -1; }
this (int val) { ndx_ = val; }
int ndx() { return ndx_; }
}
// some to test with a simple class
AARLTest1[] t1;
for (int i = 0; i < 10; i++) t1 ~= new AARLTest1(i);
// t1t and instance of AARL2!AARLTest1 to run the tests on,
i.e., "t1 tests"
auto t1t = new AARL2!AARLTest1 (t1);
assert (t1t.length == 10, "t1t.length != 10");
t1t.push (new AARLTest1(11));
assert (t1t.length == 11, "t1t.length != 11");
// t1ta the first auxillary variable for the testing.
auto t1ta = t1t.pop ();
assert (t1t.length == 10, "t1t.length != 10");
assert (t1ta.ndx() == 11, "t1ta.ndx() != 11");
assert (t1ta !in t1t, "Oop1! t1ta in t1t");
// t1tb the second auxillary variable for the testing.
auto t1tb = t1t.popR ();
assert (t1t.length == 9, "t1t.length != 9");
assert (t1tb !in t1t, "Oop2! t1tb in t1t");
t1ta = t1t.readR();
assert (t1t.length == 9, "t1t.length != 9");
assert (t1ta in t1t, "Oop3! t1ta !in t1t");
// t1t.append (t1tb);
t1t ~= t1tb;
assert (t1t.length == 10, "t1t.length != 10");
assert (t1tb in t1t, "Oop4! t1tb !in t1t");
t1t.removeKey(t1tb.ndx);
assert (t1tb !in t1t, "Oop5! removeKey failed.");
t1t.remove (t1ta);
assert (t1ta !in t1t, "Oop6! remove failed.");
}
--
Javascript is what you use to allow third part programs you don't know anything about and doing you know not what to run on your computer.
More information about the Digitalmars-d-learn
mailing list