OpSlice for Ndim arrays?

Oskar Linde olREM at OVEnada.kth.se
Sat Mar 11 03:00:26 PST 2006


S. Chancellor wrote:

> It would be nice if the .. operator just returned a variable of a
> sequence type template.  That would make it more useful than the
> current limitations of being in a [] operator.  Lots of other language
> features could take advantage of sequence types.  Then:
> 
> " But then, what about mixed expressions like 'a[1,4..7]' ?" Wouldn't
> have alot of baring, it would just be a vararg function, one element
> would be an int, while another would be a sequence.

The problem with vararg functions is that the argument types are resolved at
runtime. This is what Norbert calls "not an option". First, the only way to
make this fast is to hope that the indexing function gets inlined, its
loops unrolled and the type information constantly folded in.
Multidimensional arrays are often used where speed matters, so indexing
should be as fast as possible. But this is not the main problem. The
resulting type of an indexing expression depends on whether dimensions are
indexed or sliced. A three dimensional array a, indexed like a[0..1,0,0..5]
should result in a two dimensional array (sliced dimensions remain, indexed
dimensions are removed). The return type has to be computed at compile
time.

I was going to post this at this moment, but reading Norberts post again
gave me an idea I had to test...:

> On 2006-03-10 07:34:31 -0800, Norbert Nemec <Norbert_member at pathlink.com>
> said: 
>> All the really clean solution that I could think of would demand for
>> tuple-types and list-handling at compile time, both things that have been
>> discussed before but are at best a topic for the very far future.

It turns out this is not at all far away. Compile time varadic function
arguments are available with the IFTI support in DMD 0.149. That means
today!

(Allright, not unlimited number of varadic function arguments, but a
reasonable number of arguments at least.)

Here is a demo:

---
import std.stdio;

struct Empty {}

template TupleType(A = Empty, B = Empty, C = Empty, D = Empty, E = Empty, F
= Empty, G = Empty /*,...*/) {
  static if (is(A == Empty))
    alias Empty TupleType;
  else
    alias List!(A,.TupleType!(B,C,D,E,F,G/*,...*/)) TupleType;
}

template Tuple(A = Empty, B = Empty, C = Empty, D = Empty, E = Empty, F =
Empty, G = Empty /*,...*/) {
  TupleType!(A,B,C,D,E,F,G /*,...*/) Tuple(A a = A.init, B b = B.init, C c =
C.init, D d = D.init, E e = E.in\
it, F f = F.init, G g = G.init /*,...*/) {
    static if (is(A == Empty))
      return Empty.init;
    else
      return List!(A,TupleType!(B,C,D,E,F,G/*,...*/)
(a,.Tuple(b,c,d,e,f,g /*,...*/));
  }
}

struct List(A,B) {
  A head;
  B tail;
  static List opCall(A a, B b) {
    List!(A,B) ret;
    ret.head = a;
    ret.tail = b;
    return ret;
  }
}

template func(A = Empty, B = Empty, C = Empty, D = Empty, E = Empty, F =
Empty, G = Empty /*, ...*/) {
    void func(A a = A.init, B b = B.init, C c = C.init, D d = D.init, E e =
E.init, F f = F.init, G g = G.ini\
t /*,...*/) {
      realFunc(Tuple(a,b,c,d,e,f,g /*,...*/));
  }
}

template realFunc(T) {
  void realFunc(T args) {
    static if (is(T == Empty)) {
      writefln("Done!");
    } else {
      writefln("Got argument: (%s) %s",typeid(typeof(args.head)),args.head);
      .realFunc(args.tail);
    }
  }
}

void main() {
  int a = 1;
  float b = 5.6;
  long c = 3;
  char[] d = "test";
  func(a,b,c,d);
}

---

And guess what? This prints:

Got argument: (int) 1
Got argument: (float) 5.6
Got argument: (long) 3
Got argument: (char[]) test
Done!

All types are deduced at compile time!

Notice the neat implementation of realFunc(). All other templates could be
put in a library. I bet the func()-wrapper could declared by a mixin!

So all we need to support multidimensional splice/indexing is to make ..
evaluate into:

struct Sequence {
        size_t start,end;
}

and we are set.

/Oskar



More information about the Digitalmars-d mailing list