Testing array ptr for offset 0...

Era Scarecrow via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu May 26 14:13:14 PDT 2016


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.


More information about the Digitalmars-d-learn mailing list