| |
| Posted by Charles Hixson in reply to Ali Çehreli | PermalinkReply |
|
Charles Hixson
Posted in reply to Ali Çehreli
| 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.
|