Thread overview
template parameters
Aug 29, 2021
Charles H.
Aug 29, 2021
Ali Çehreli
Aug 29, 2021
Charles Hixson
Aug 30, 2021
Ali Çehreli
Sep 02, 2021
Charles Hixson
Sep 02, 2021
H. S. Teoh
Re: template parameters :: fix
Sep 03, 2021
Charles Hixson
August 29, 2021

I've set up a class template (so far untested) thus:

class    AARL (T, ndx = "ndx")
        if (isIntegral(T.init.ndx) )

If I'm correct, this should work for ndx an integer variable of T, but I'd really like T to be able to be anything which can be stored both in an array and in an associative array.  But I can't figure out how to specify ndx.  After all, T might be a float, so it wouldn't have any appropriate attributes.  And I'd also like ndx to be able to be a function either a member of the class/struct T or a stand alone function.

So how should I set up this template?

August 29, 2021
On 8/29/21 11:32 AM, Charles H. wrote:
> I've set up a class template (so far untested) thus:
> 
>      class    AARL (T, ndx = "ndx")
>              if (isIntegral(T.init.ndx) )
> 
>      If I'm correct, this should work for ndx an integer variable of T, but I'd really like T to be able to be anything which can be stored both in an array and in an associative array.  But I can't figure out how to specify ndx.  After all, T might be a float, so it wouldn't have any appropriate attributes.  And I'd also like ndx to be able to be a function either a member of the class/struct T or a stand alone function.
> 
> So how should I set up this template?
> 

I came up with the following:

template supportsCall(T, string func) {
  import std.format : format;
  import std.traits : isIntegral;

  enum expr = format!q{
    enum supportsCall = isIntegral!(typeof(T.init.%s()));
  }(func);

  mixin (expr);
}

class AARL (T, string func = "ndx")
if (supportsCall!(T, func)) {
}

int ndx(int i) {
  return 42;
}

struct S {
  long ndx() {
    return 100;
  }
}

void main() {
  auto a = new AARL!int();
  auto b = new AARL!S();
}

Ali

August 29, 2021
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.


On 8/29/21 2:41 PM, Ali Çehreli via Digitalmars-d-learn wrote:
> On 8/29/21 11:32 AM, Charles H. wrote:
>> I've set up a class template (so far untested) thus:
>>
>>      class    AARL (T, ndx = "ndx")
>>              if (isIntegral(T.init.ndx) )
>>
>>      If I'm correct, this should work for ndx an integer variable of T, but I'd really like T to be able to be anything which can be stored both in an array and in an associative array.  But I can't figure out how to specify ndx.  After all, T might be a float, so it wouldn't have any appropriate attributes.  And I'd also like ndx to be able to be a function either a member of the class/struct T or a stand alone function.
>>
>> So how should I set up this template?
>>
>
> I came up with the following:
>
> template supportsCall(T, string func) {
>   import std.format : format;
>   import std.traits : isIntegral;
>
>   enum expr = format!q{
>     enum supportsCall = isIntegral!(typeof(T.init.%s()));
>   }(func);
>
>   mixin (expr);
> }
>
> class AARL (T, string func = "ndx")
> if (supportsCall!(T, func)) {
> }
>
> int ndx(int i) {
>   return 42;
> }
>
> struct S {
>   long ndx() {
>     return 100;
>   }
> }
>
> void main() {
>   auto a = new AARL!int();
>   auto b = new AARL!S();
> }
>
> Ali
>
-- 
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.

August 29, 2021
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

September 02, 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.

September 02, 2021
On Thu, Sep 02, 2021 at 02:28:23PM -0700, Charles Hixson via Digitalmars-d-learn wrote: [...]
> -- 
> 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.

ROFL!  I'm st^Wborrowing this for my quotes file. ;-)


T

-- 
"How are you doing?" "Doing what?"
September 03, 2021
change:

            {    rl.remove(i);

to:

           {    rl  =  rl.remove(i);

-- 
Javascript is what you use to allow third party programs you don't know anything about and doing you know not what to run on your computer.