New abstraction: Layout

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Wed Feb 21 03:56:52 UTC 2018


On 02/20/2018 07:34 AM, Steven Schveighoffer wrote:
> On 2/18/18 4:52 AM, Dmitry Olshansky wrote:
>> On Saturday, 17 February 2018 at 19:37:12 UTC, Steven Schveighoffer 
>> wrote:
>>> On 2/17/18 9:59 AM, Andrei Alexandrescu wrote:
>>>> On 02/17/2018 09:03 AM, Steven Schveighoffer wrote:
>>>>> I found this also works:
>>>>>
>>>>> static foreach(alias x; S.tupleof)
>>>>> {
>>>>>     writeln(x.offsetof);
>>>>> }
>>>>
>>>> Yes, the implementation uses offsetof.
>>>>
>>>
>>> I guess I'm just confused based on the statement "the builtin 
>>> .tupleof ... [omits] the essential information of field offsets."
>>>
>>> What is this construct giving us that .tupleof doesn't?
>>>
>>
>> I guess the construct captures offsets as part of type. This is useful 
>> for allocators + 2 things with same Layout can be bitblitted to each 
>> other.
> 
> I haven't looked at it in depth, so I didn't know the result of the 
> abstraction (I thought it was a tuple, or a pair of tuples).
> 
> Note, you could do this without the need for a new abstraction, simply 
> with .tupleof on the type itself.
> 
> And static foreach has made this much simpler. But definitely the 
> interface to getting things from tupleof is not consistent. This reason 
> alone may be cause to add such a construct.

There's the difference that with inline static foreach you can express 
one processing of one layout, whereas with a structured result you can 
express the notion of any processing of any layout. The distinction 
between an inlined for loop and the map function comes to mind.

In particular, static foreach would be a good implementation device for 
Layout. I happened to express it a different way because it seemed 
simpler, but contributions welcome.

Next step is to manipulate layouts. I have in mind an algorithm 
"eraseNonPointerTypes". It does the following. Consider:

struct A
{
     int a, b;
     string x;
     double c;
     int[] y;
}

So the layout is Layout!(0, int, 4, int, 8, string, 24, double, 32, 
int[]). Next we want to not care about non-pointers - just merge all 
that nonsense together. So eraseNonPointerTypes applied to this layout 
would yield Layout!(0, ubyte[8], 8, string, 24, ubyte[8], 32, int[]).

At this point we figure that this partially erased layout is the same as 
for this other type:

struct B
{
     double a;
     string b;
     long c;
     int[] d;
}

And the ba dum tss of it all is that you can allocate an A, deallocate 
it, then allocate a B in the same memory - all in safe code. Even if you 
have a dangling pointer to A messing with a B object, the code will be 
incorrect but will not lose memory safety.

This is a major part of Alexandru Jercaianu's work on Blizzard - a 
memory-safe allocation framework. I am so excited about the impending 
release I can't stand myself.


Andrei



More information about the Digitalmars-d mailing list