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.