On Thursday, 26 May 2016 at 11:47:13 UTC, ag0aep6g wrote:
I don't follow. Why can't you use a built-in array? What can you do with the stand-in that you can't do with the array itself?

I can do the job with the built-in arrays, however the need for another temporary array to keep track of lengths so I can slice them after the fact is what i want to avoid. I'm also slicing static arrays. I'm trying to see if this code would be more efficient or not (if it is, it's not by much, which I'm sure has to do with the cache more than anything else).

 To do what I want currently it's something like...

  enum Size = 1024, Other = 128;
  Data[Size][Other] staticarray;  //stack allocation
  Data[][] sliced = staticarray[];
  scan(sliced, condition);

  void scan(ref Data[][] data, Condition cond) {
    int lengths[Size];

    foreach(i; ...) {
      if (cond)
        data[i][lengths[i]++] = ...
    }

    //cleanup/shrink
    foreach(i, l; lengths)
      data[i] = data[i][0 .. l];
  }

By adding a struct overload for opOpAssign I can shrink it all down to this, and avoid lengths entirely... As such internally the length starts at 0, and checks are in place to ensure the bounds are never exceeded.

  void scan(ref Data[][] data, Condition cond) {
    foreach(i; ...) {
      if (cond)
        data[i] ~= ...
    }
  }


Seems a bit back and forth, but as far as I can see it works as you want. Why do you think the answer it gives is wrong? What answer does it give you?

The answer is wrong _because_ the code blows up. I inverted the check to check if length is at offset 0 since (the length can only be 1 and a better test), however it _still_ gives the wrong answer. Curiously CTFE is fine with this casting as long as the pointer stays in that one spot.

template isArrayLengthOffsetZero() {
  bool check() {
    size_t[] arr = new size_t[1];
    return *(cast(size_t*) &arr) == 1;
  }

  enum isArrayLengthOffsetZero = check(); //wrong answer
// enum isArrayLengthOffsetZero = !check(); //right answer but logically wrong
}

//test struct
struct S(T) {
  static if (isArrayLengthOffsetZero!()) {
    size_t length;
    T* ptr;
  } else {
    T* ptr;
    size_t length;
  }

  this(T* p) { ptr = p; }
  //opOpAssign
}

unittest {
  import std.stdio;

  //union to get our overlapping data types
  union X { string str; S!(immutable char) s_str;}
  X x;
  x.s_str = S!(immutable char)("t".ptr); //only ptr assigned

  //writeln(x.str);          //blows up
  writeln(x.str.length);     //not 0...
  assert(x.str.length == 0); //fails
}


Most likely the internal array structure CTFE uses for the array is inverted, and if that's the case the proper answer to how to get the simple offset of ptr (or length) is a mess.

Forcing the inverted answer works, but this is a lot of overhead to try and make an algorithm faster. Speedups are minimal at best, so I'm about ready to drop this line of thought.

Reply via email to